Framework/Spring

Spring-Annotation(어노테이션)

보라색츄르 2021. 6. 15. 15:47

※스프링에서 가장 중요

 Annotation이란? 

     Annotation의 사전적 의미로는 주석이라는 뜻이다. 자바에서 사용될 때의 Annotation은 코드 사이에 주석처럼

     쓰여서 특별한 의미, 기능을 수행하도록 하는 기술이다. 즉, 프로그램에게 추가적인 정보를 제공해주는

     메타데이터라고 볼 수 있다.

1. Annotation의 설정 기초

     1) Context 네임스페이스 추가

         <beans>에 Context관련 네임스페이스와 스키마 문서의 위치를 등록해야 한다. 

         방법 : [Namespaces]→'context'항목 체크!

    2) Component-scan설정

         스프링 설정 파일에 애플리케이션을 사용할 객체들을 <bean>등록하지 않고 자동으로 생성하려면 

         <context:componenet-scan/>이라는 엘리먼트를 정의해야 한다. 이 설정을 추가하면 스프링 컨테이너는 

        클래스 패스에 있는 클래스들을 스캔하여 @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: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
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">

	<context:component-scan base-package="com.springbook.biz"></context:component-scan>
</beans>

        ※부가설명

        <context:component-scan base-package="com.springbook.biz"></context:component-scan> :  

        이 뜻은 com.springbook.biz패키지로 시작하는 모든 패키지를 스캔 대상에 포함한다.

        따라서 다음과 같은 모든 패키지의 클래스들이 스캔 대상이 된다!!

 

 

   3) Annotation의 선언 및 특징

       ㄱ) @Component : 개발자가 직접 작성한 Class를 Bean으로 등록하기 위한 Annotation!

                                 ※주의! 해당 클래스에 기본 생성자가 있어야만 컨테이너가 객체를 생성할 수 있다.

                                   또한 Component에 사용할 아이디나 이름이 반드시 설정되어 있어야 한다. 

                                   만일 설정이 누락된다면  LgTV 앞 영문은 소문자로 바뀌어 lgTV로 자동 부여 된다. 

/**XML**/
<?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:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p"
	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="di.anno"></context:component-scan>
</beans>


/**Class**/
package di.anno;
@Component("tv") 
public class LgTV implements TV {
	public LgTV(){System.out.println("===>LgTV 객체 생성");}
	public void powerOn() {System.out.println("LgTV---전원on");}
	public void powerOff() {System.out.println("LgTV---전원off");}
 }
 
 
 /**MAIN**/
package di.anno;

public class TVuserDIAnno {
	public static void main(String[] args) {
		AbstractApplicationContext factory =new GenericXmlApplicationContext("applicationContext.xml");	
		TV tv=(TV)factory.getBean("tv");		
		tv.powerOff();
	    tv.powerOn();
		factory.close();
	}
}

    ㄴ ) @Autowired :- 의존성 주입을 지원하는 어노테이션

                            - 생성자나 메소드, 멤버변수 위에 모두 사용할 수 있다. 어디에 사용하든 결과가 같아서

                               상관없지만 주로 변수 또는 멤버변수 위에 설정하여 해당 타입의 객체를 찾아서 자동으로

                               할당한다.

                            - 스프링 컨테이너는 @Autowired를 확인하는 순간 해당 변수의 타입을 체크한다. 그리고

                              그 타입의 객체가 메모리에 존재하는지를 확인한 후에, 그 객체를 변수에 주입한다.

                              만약 메모리에 없다면 NoSuchBeanDefinitionException을 발생시킨다.

                              해결방안 1. 설정파일에 <bean></baen> 태그(엘리먼트)를 이용하여 컨테이너

                                             구동시 자동 생성될 수 있도록 설정
                              해결방안 2. 해당 타입을 갖는 클래스선언부 위에 @Component를 설정하여 설정파일의

                                            <context:component-scan~~></context:component-scan>에 의해서

                                             자동 검색할 수 있도록 설정

/**XML**/
<?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:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p"
	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="di.anno"></context:component-scan>
	<bean class="di.anno.SonySpeaker"></bean>
</beans>


/**Class**/
package di.anno;
@Component("tv") 
public class LgTV implements TV {
	
	@Autowired
	private Speaker speaker;

	public LgTV(){System.out.println("===>LgTV 객체 생성");}	
	@Override
    public void powerOn() {System.out.println("LgTV---전원on");}
	@Override	
    public void powerOff() {System.out.println("LgTV---전원off");}
	@Override	
    public void volumeUp() {this.speaker.volumeUp();}
	@Override	
    public void volumeDown() {this.speaker.volumeDown();}
}


/**SonySpeaker**/
package di.anno;

@Component("sony")
public class SonySpeaker implements Speaker {
	public SonySpeaker() {System.out.println("SonySpeaker 객체 생성");}
	@Override
	public void volumeUp() {System.out.println("SonySpeaker 소리 Up");}
	@Override
	public void volumeDown() {System.out.println("SonySpeaker 소리Down");}
}

ㄷ ) @Qualifier :

     -의존성 주입을 지원하는 어노테이션

     - Spring Container 내에 동일한 타입을 갖는 개체가 여러개 일 경우 특정 객체를 지정하여 Spring Container가

       혼돈하지 않도록 설정..

     예) SonySpeaker / AppleSpeaker 클래스가 Speaker인터페이스를 구현받았다고 가정

           <bean id="sony" class="di.anno.SonySpeaker"></bean> <!-- <==Speaker타입-->

            <bean id="apple" class="di.anno.AppleSpeaker"></bean> <!-- <==Speaker타입-->

 

                         @Component("tv")

                            public class LgTV implements TV{

                         

                             @Autowired  <!-- ==> Speaker 타입 객체를 검색 -->

                            @Qualifier("apple") <!-- <==와 같이 특정 객체를 설정 -->

                             private Speaker speaker;

                             //중간 생략..

                         }

 ※ 만약  @Qualifier("apple")을 지정하지 않았을 경우 발생하는 에러 ※

Could not autowire field: private di.anno.Speaker di.anno.LgTV.speaker; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [di.anno.Speaker] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.

ㄹ ) @Inject :

     - 의존성 주입을 지원하는 어노테이션

     -  @Autowired와 동일한 기능을 제공한다.

ㅁ ) @Resource :

     - 의존성 주입을 지원하는 어노테이션

     - @Autowired와 @Qualifier의 기능을 결합한 어노테이션,  객체 이름을 이용하여 주입

    ※ 참고 : @Autowired는 타입을 이용하여 의존성 주입 ※

     즉, 동일한 타입의 객체가 여러 개일 경우 @Autowired는 @Qualifier("apple")와 같이 추가로 지정해 주어야 하지만,

     @Resource는 @Resource(name="apple")와 같이 지정할 수 있다.

     따라서, @Autowired가 있는 멤버변수의 타입과 동일한 타입을 갖는 객체가 1개만 존재할 경우에는 @Autowired를        사용 여러개일 경우에는 @Resource가 편리하다. 만약 해당 이름(name="apple")을 찾을수 없는 경우에는    

     에러 발생한다.

ㅅ ) @Service :

     - 비즈니스로직을 처리하는 Service클래스

    - 비즈니스로직이란? SeviceImpl 클래스들로 이루어진다. 즉, 고객이 원하는 프로그램에 대해 원하는 것이 무엇인지

      파악하고 이를 전체적으로 로직화 하는 것을 말한다. 한마디로 말하면 프로그램 전체 모듈이라고도 할 수 있겠다.   

ㅇ ) @Repository :

    - 데이터베이스 연동을 처리하는 DAO 클래스

ㅈ ) @Controller :

    - 사용자 요청을 제어하는 Controller클래스

※ ㅅ~ㅈ를 사용하는 이유는 모든 클래스에 @Componenet를 할당하면 어떤 클래스가 어떤 역할을 수행하는지 파악하기가 어렵다. 따라서 스프링 프레임 워크에서 클래스를 분류하기 위해서 @Component를 상속하여 ㅅ~ㅈ과 같은 세개의 어노테이션을 추가로 제공한다.

 


 

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

 

1) 어노테이션과 XML설정을 병행하여 사용하는 이유는?

XML방식은 자바 소스를 수정하지 않고 XML파일의 설정만 변경하면 실행되는 Speaker를 교체할 수 있어 유지보수가 편하지만 XML설정에 대한 부담이 크고, 자바 소스에 의존관계와 관련된 어떤 메타데이터도 없으므로 XML설정을 해석해야만 무슨 객체가 주입되는지를 확인할 수 있다.

 

 

2) 어노테이션과 XML설정을 병행하여 사용하면? 

XML 설정에 대한 부담도 없도, 의존 관계에 대한 정보가 자바 소스에 들어 있어서 사용하기 편하다. 하지만 의존 주입할 객체의 이름이 자바소스에 명시되어야 하므로 자바 소스를 수정해야 한다.

 

 

3) 어노테이션과 XML설정을 병행하여 잘 사용하려면?

1) 특정 컴포넌트에 주입되는 객체가 자주 변경 되어야 할 경우에는 <bean~~>으로 설정</bean~~>

2) 특정 컴포넌트에 주입되는 객체가 고정일 경우에는

   ㄱ) 주입되는 클래스에 @Component를 설정하고 주입받는 클래스 내부에 변수에는 @Autowired를 이용하여 설정

   ㄴ) 또는 주입받는 클래스 내부의 변수에는 @Autowired와 @Qualifier("객체명")를 이용하여 설정

단! ~~.jar 처럼 라이브러리 형태로 제공되는 클래스는 반드시 설정파일 내에 <bean~~></bean>의 형태로 설정한다.

예)개발자가 선언하는 클래스는 어노테이션 또는 xml형태를 선택 톰캣, 스프링 프레임워크가 제공하는 클래스는 반드시 

<bean~~></bean>으로 지정 스프링이 제공하는 DispatcherServlet클래스 처럼!!!!