[Spring] 어노테이션 (@, annotation)
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>