본문 바로가기

Spring

[Spring] 어노테이션 (@, annotation)

728x90
반응형

Annotation이란 사전적 의미로 주석이라는 뜻

 

"xml은 설정이 과도하다."

하나의 클래스 내부에 
여러개의 객체 멤버변수 
+
bean(등록된 객체)의 수가 多

=> 개발자들은, JAVA 코드와 함께 의존관계를 파악하기를 선호 
     그냥 "JAVA 코드에 xml 설정을 추가"해보자! 
      그래서 탄생한게 어노테이션 (@) 


어노테이션 사용법

 

1. 초기설정을 위해서 Naemspaces에서 context 추가 

Source로 돌아오면 하기 코드가 추가됨

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

 

2. 컴포넌트 스캔 설정
어노테이션을 컨테이너가 사전에 스캔할 예정 
그러므로 스캔 범위를 지정해줘야한다! 

 

<context:component-scan> 태그를 사용하고 

base-package는 필수속성으로 참조해야할 패키지명을 기입 

<?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:component-scan base-package="test"/>

</beans>

 

3.  @Component 사용 

 

@Component 

  • 개발자가 직접 작성한 Class를 Bean으로 등록하기 위한 어노테이션
  • @Bean과 다르게 @Component는 name이 아닌 value를 이용해 Bean의 이름을 지정

 

IPhone에서 상단에 @Component를 입력하는데 <bean> 등록없이 자동으로 객체가 생성 됨

@Component("ip")  == <bean id="ip" class="test.IPhone"> or new IPhone(); 과 동일 

@Component("ip")로 Lookup을 해줌 

package test;

import org.springframework.stereotype.Component;

@Component("ip") // <bean id="ip" class="test.IPhone"> or new IPhone(); 과 동일 
public class IPhone implements Phone{
	private Watch watch; //객체 맴버변수 이기 때문에 의존관계 -< 의존성 주입(DI)이 필요한 상태 
	private int number;
	
	//생성자
	public IPhone() {
		System.out.println("아이폰 객체 생성완료");
	}	
	// 생성자 인젝션 
	public IPhone(Watch watch) { //외부에서 받아온걸로 생성자 new 
		System.out.println("아이폰 객체 생성 완료22");
		this.watch=watch;
	}
	public IPhone(Watch watch, int number) { //외부에서 받아온걸로 생성자 new 
		System.out.println("아이폰 객체 생성 완료33");
		this.watch=watch;
		this.number=number;
	}
	@Override
	public void powerOn() {
		System.out.println("아이폰 전원 ON : " + this.number);
		
	}
	@Override
	public void powerOff() {
		System.out.println("아이폰 전원 OFF");
	}
		
	@Override
	public void volumeUp() {
		//System.out.println("아이폰 소리 ++");
		watch.volumeUp();
	}
	@Override
	public void volumeDown() {
		//System.out.println("아이폰 소리 --");
		watch.volumeDown();
	}
}

 

클라이언트에서 IPhone poweron, volumeup 실행 

package test;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Client {
	public static void main(String[] args) {
		//Spring 컨테이너를 동작시킬 수 있도록 코드작성 
		AbstractApplicationContext factory=new GenericXmlApplicationContext("applicationContext.xml");
		Phone phone=(Phone)factory.getBean("ip");
		phone.powerOn();
		phone.volumeUp();
		factory.close();
	}
}

 

volumeup의 메서드를 수행하기 위해서는 watch 객체가 초기화(new)를 해주어야하는데 

그렇지않아서 오류 발생 이를 해결하기 위해서는 의존성 주입이 필요! (@Autowired) 

 

3.  의존성 주입 (DI) 

 

3-1) @Autowired 

  • 멤버변수 뿐아니라 메서드, 생성자에서도 사용가능
  • 해당 멤버변수의 "타입"을 체크 
  • 메모리를 확인해서 같은 타입을 주입함 
package test;

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

@Component("ip") // <bean id="ip" class="test.IPhone"> or new IPhone(); 과 동일 
public class IPhone implements Phone{
	
	@Autowired // 의존성 주입
	private Watch watch; //객체 맴버변수 이기 때문에 의존관계 -< 의존성 주입(DI)이 필요한 상태 
	private int number;
	
	//생성자
	public IPhone() {
		System.out.println("아이폰 객체 생성완료");
	}	
	// 생성자 인젝션 
	public IPhone(Watch watch) { //외부에서 받아온걸로 생성자 new 
		System.out.println("아이폰 객체 생성 완료22");
		this.watch=watch;
	}
	public IPhone(Watch watch, int number) { //외부에서 받아온걸로 생성자 new 
		System.out.println("아이폰 객체 생성 완료33");
		this.watch=watch;
		this.number=number;
	}
	@Override
	public void powerOn() {
		System.out.println("아이폰 전원 ON : " + this.number);
		
	}
	@Override
	public void powerOff() {
		System.out.println("아이폰 전원 OFF");
	}
		
	@Override
	public void volumeUp() {
		//System.out.println("아이폰 소리 ++");
		watch.volumeUp();
	}
	@Override
	public void volumeDown() {
		//System.out.println("아이폰 소리 --");
		watch.volumeDown();
	}
}

 

@Autowired 만 추가하고 다시 실행해보면 하기와 같이 오류가 또 발생 

 

이를 해결하기 위해서는 객체화를 해주면 되는데

 

첫번째 방법  : 설정 파일에서 사용하려는 watch를 <bean> 해줌 

	<context:component-scan base-package="test"/>
	<!-- 필수 속성으로 base-package에서 어딜 스캔할지 결정  -->
	<bean id="aw" class="test.AppleWatch"></bean>
	
	</beans>

 

두번째 방법  : 사용하고자 하는 watch의 클래스 상단에 @Component를 기입

package test;

import org.springframework.stereotype.Component;

@Component
public class AppleWatch implements Watch{
	
	public AppleWatch() {
		System.out.println("애플워치 객체생성완료");
	}
	public void volumeUp() {
		System.out.println("애플워치 ++");
	}
	public void volumeDown() {
		System.out.println("애플워치 --");
	}
}

 

3-2) @Qualifier

 

만약 여러개의  watch의 객체를 초기화 하려고 한다면 오류가 발생되는데 

Autowired 모호성의 문제 때문!

이를 해결하기 위해서 이름으로 지정하는 @Qualifier 사용

 

GalaxyWatch, AppleWatch에 @Component 추가한 후 

package test;

import org.springframework.stereotype.Component;

@Component("aw")
public class AppleWatch implements Watch{
	
	public AppleWatch() {
		System.out.println("애플워치 객체생성완료");
	}
	public void volumeUp() {
		System.out.println("애플워치 ++");
	}
	public void volumeDown() {
		System.out.println("애플워치 --");
	}
}
package test;

import org.springframework.stereotype.Component;

@Component("gw")
public class GalaxyWatch implements Watch{
	
	public GalaxyWatch(){
		System.out.println("갤럭시워치 객체생성완료");
	}
	@Override
	public void volumeUp() {
		System.out.println("갤럭시워치 ++");
		// TODO Auto-generated method stub
		
	}
	@Override
	public void volumeDown() {
		System.out.println("갤럭시워치 --");
		// TODO Auto-generated method stub
		
	}
}

 

IPhone 클래스에서  @Qualifier("참조할 객체명") 기입

저는 GalaxyWatch를 불러내기 위해서 "gw" 

package test;



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

@Component("ip") // <bean id="ip" class="test.IPhone"> or new IPhone(); 과 동일 
public class IPhone implements Phone{
	
	@Autowired // 의존성 주입
	@Qualifier("gw")
	private Watch watch; //객체 맴버변수 이기 때문에 의존관계 -< 의존성 주입(DI)이 필요한 상태 
	private int number;
	
	//생성자
	public IPhone() {
		System.out.println("아이폰 객체 생성완료");
	}	
	// 생성자 인젝션 
	public IPhone(Watch watch) { //외부에서 받아온걸로 생성자 new 
		System.out.println("아이폰 객체 생성 완료22");
		this.watch=watch;
	}
	public IPhone(Watch watch, int number) { //외부에서 받아온걸로 생성자 new 
		System.out.println("아이폰 객체 생성 완료33");
		this.watch=watch;
		this.number=number;
	}
	@Override
	public void powerOn() {
		System.out.println("아이폰 전원 ON : " + this.number);
		
	}
	@Override
	public void powerOff() {
		System.out.println("아이폰 전원 OFF");
	}
		
	@Override
	public void volumeUp() {
		//System.out.println("아이폰 소리 ++");
		watch.volumeUp();
	}
	@Override
	public void volumeDown() {
		//System.out.println("아이폰 소리 --");
		watch.volumeDown();
	}
}

 

하기와 같이 오류없이 아이폰, 갤럭시워치가 정상 출력 

 


 

@Autowired의 대상이 @Component로 되어있는것이 
때로는 불리할때도 있기 때문에 

@ 와 xml을 같이 사용!! 

 

위에서 지정해 두었던 @Qualifier 삭제하고 xml 파일에서 의존성 주입 객체를 지정해주면 됨!! 

@Autowired가 IPhone에 선언된 watch를 조회할텐데 <bean>으로 AppleWatch에 있는 객체가 초기화(new) 되기 때문에

AppleWatch, GalaxyWatch 클래스 객체에는  @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:component-scan base-package="test"/>
	<bean  class="test.AppleWatch"></bean>
	</beans>
728x90
반응형