목차

 

  1. Custom Annotation 만들고 사용하기

 

  2. @RequestMapping 들여다 보기

 

 

 

Custom Annotation 만들고 사용하기

 

   ※ Custom Annotation 생성

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
	String name()	default "Gyu";		//name값을 설정할 수 있으며, 아무런 값을 넣지 않으면 Gyu가 들어갑니다.
	String value();							//value값을 설정할 수 있으며, 아무런 값을 넣지 않으면 Syntax error가 발생합니다.
	int count()	default 1;							//기본 자료형도 사용할 수 있습니다
	String[] arrName()	default "first Index";		//배열값을 넣을 수 있습니다. { }안에 값을 넣어 삽입. 
	TestEnumType[] testEnumType()		default TestEnumType.FIRST;	//enum타입의 값을 설정할 수 있습니다.
	AnnoDateTime annoDateTime();	//Annotation안에 또 다른 Annotation값을 넣을 수 있습니다.
}

@Retention(RetentionPolicy.RUNTIME)
@interface AnnoDateTime {
	String yymmdd();
	String hhmmss();
}

enum TestEnumType {
	FIRST, FINAL
}

 

Custom Annotation을 작성하기 위해 몇 가지 규칙이 존재합니다.

 

1. 요소의 타입은 기본형, String, enum, 어노테이션, Class만 허용된다.

2. 요소의 ()안에 매개변수를 선언할 수 없다.

3. 예외를 선언할 수 없다.

4. 요소를 타입 매개변수로 정의할 수 없다.

5. 어노테이션의 각 요소는 기본값을 가질 수 있다.

 

위 규칙을 생각하며 어노테이션을 작성하면 됩니다.

 

   ※ Custom Annotation 적용

 

   - 클래스에 선언

@MyAnnotation(value = "First Text", annoDateTime = @AnnoDateTime(yymmdd = "190924", hhmmss = "101147"))
public class AnnotationHandler {
	
	public String myField = null;
	
	public void doThis() {
		
	}
	
	public void doThat() {
		
	}
	
}

 

   - 클래스 필드에 선언

public class AnnotationHandler {
	
	@MyAnnotation(value = "First Text", annoDateTime = @AnnoDateTime(yymmdd = "190924", hhmmss = "101147"))
	public String myField = null;
	
	public void doThis() {
		
	}
	
	public void doThat() {
		
	}
	
}

 

   - 메서드에 선언

public class AnnotationHandler {
	
	public String myField = null;
	
	@MyAnnotation(value = "First Text", annoDateTime = @AnnoDateTime(yymmdd = "190924", hhmmss = "101147"))
	public void doThis() {
		
	}
	
	@MyAnnotation(value = "First Text", annoDateTime = @AnnoDateTime(yymmdd = "190924", hhmmss = "101147"))
	public void doThat() {
		
	}	
}

 

   

  ※ 자바 리플렉션으로 커스텀 어노테이션 사용하기

 

@Retention(RetentionPolicy.RUNTIME)값으로 설정한 Custom Annotation은 런타임 시점에 어노테이션 정보를 이용하여 코드를 생성합니다.

이러한 이유로 RUNTIME옵션을 설정한 Custom Annotation은 자바 리플렉션을 사용하여 선언한 어노테이션 값을 가져옵니다.

 

프로그램 구동 시, Custom Annotation에서 어떤 값이 넘어오는지 확인해보는 테스트를 해보겠습니다.

 

MyAnnotation.java

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
	String name()	default "Gyu";		//name값을 설정할 수 있으며, 아무런 값을 넣지 않으면 Gyu가 들어갑니다.
	String value();							//value값을 설정할 수 있으며, 아무런 값을 넣지 않으면 Syntax error가 발생합니다.
	int count()	default 1;							//기본 자료형도 사용할 수 있습니다
	String[] arrName()	default "first Index";		//배열값을 넣을 수 있습니다. { }안에 값을 넣어 삽입. 
	TestEnumType[] testEnumType()		default TestEnumType.FIRST;	//enum타입의 값을 설정할 수 있습니다.
	AnnoDateTime annoDateTime();	//Annotation안에 또 다른 Annotation값을 넣을 수 있습니다.
}

@Retention(RetentionPolicy.RUNTIME)
@interface AnnoDateTime {
	String yymmdd();
	String hhmmss();
}

enum TestEnumType {
	FIRST, FINAL
}

 

AnnotationHandler.java

@MyAnnotation(value = "Class => AnnotationHandler", testEnumType = TestEnumType.FINAL,annoDateTime = @AnnoDateTime(yymmdd = "091005", hhmmss = "000000"))
public class AnnotationHandler {
	
	@MyAnnotation(value = "Field => myField", count = 10, annoDateTime = @AnnoDateTime(yymmdd = "131224", hhmmss = "210556"))
	public String myField = null;
	
	@MyAnnotation(value = "Method => doThis()", testEnumType = TestEnumType.FIRST, annoDateTime = @AnnoDateTime(yymmdd = "190924", hhmmss = "101147"))
	public void doThis() {
		
	}
	
	@MyAnnotation(value = "Method => doThat()", testEnumType = TestEnumType.FINAL, annoDateTime = @AnnoDateTime(yymmdd = "180728", hhmmss = "181447"))
	public void doThat() {
		
	}
	
}

 

AnnotationStudy.java

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class AnnotationStudy {

	public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException {
		
		//자바 리플렉션을 사용해 Class정보, getField(필드 정보), getMethod(메서드 정보)를 얻어옵니다.
		Class<AnnotationHandler> cls = AnnotationHandler.class; 	
		Field field = AnnotationHandler.class.getField("myField");
		Method thisMethod = AnnotationHandler.class.getMethod("doThis");
		Method thatMethod = AnnotationHandler.class.getMethod("doThat");

		//각 클래스, 필드, 메서드에 걸려있는 Annotation의 정보를 얻습니다.
		Annotation[] classAnnotations = cls.getDeclaredAnnotations();
		Annotation[] fieldAnnotations = field.getDeclaredAnnotations();
		Annotation[] thisMethodAnnotations = thisMethod.getDeclaredAnnotations();
		Annotation[] thatMethodAnnotations = thatMethod.getDeclaredAnnotations();
		
		//클래스, 메서드, 필드에 적용되어 있는 Annotation정보들을 추출합니다.
		printAnnotation(classAnnotations);
		printAnnotation(fieldAnnotations);
		printAnnotation(thisMethodAnnotations);
		printAnnotation(thatMethodAnnotations);
		
	}

	public static void printAnnotation(Annotation[] annotations) {
		
		for(Annotation annotation : annotations) {
			if(annotation instanceof MyAnnotation) {
				MyAnnotation myAnnotation = (MyAnnotation)annotation;
				
				System.out.println("String name() : " + myAnnotation.name());
				System.out.println("String value() : " + myAnnotation.value());
				System.out.println("int count() : " + myAnnotation.count());
				System.out.println("AnnoDateTime annoDateTime() yymmdd : " + myAnnotation.annoDateTime().yymmdd());
				System.out.println("AnnoDateTime annoDateTime() hhmmss : " + myAnnotation.annoDateTime().hhmmss());
				System.out.println("TestEnumType[] testEnumType() : " + myAnnotation.testEnumType());
				
				for(String str : myAnnotation.arrName()) {
					System.out.println("String[] arrName() : " + str);
				}
			}
		}
		
		System.out.println();
		
	}
}

 

출력 로그

위 소스를 보면 알다시피, RUNTIME에서 동작하는 어노테이션들은 전부 리플렉션을 사용해서 객체의 정보를 얻고, 어노테이션의 정보도 얻습니다.

 

커스텀 어노테이션을 생성해서 사용하면 반복적으로 코딩해야 하는 부분들도 많이 줄일 수 있고 더 비지니스로직에 집중할 수 있는 장점이 있습니다.

 

 

@RequestMapping 들여다 보기

 

Custom Annotation을 만들어봤으면, java 또는 Spring에서 제공하는 Annotation은 어떻게 생겼는지, 어떤식으로 구성되어 있는지 궁금하실 겁니다.

 

사실, Annotation내용을 포스팅하는 이유의 80%이상이 Annotation의 동작방식과 구성요소들을 알아보고, 직접 만들어보며 아무런 생각없이 사용하던 Annotation을 이해하자는 취지이기 때문에 @RequestMapping을 확인해보면 좀 더 친숙하게 다가갈 수 있을꺼라 생각합니다.

 

   ※ 구성 요소

 

@RequestMapping annotation 사용

위 소스는 @ReqeustMapping을 사용한 모습입니다. 익숙한 value값과 method값을 볼 수 있을 것 입니다.

실제 사용에 있어서 annotation의 인수가 하나뿐이면 value값을 지칭하지 않고 사용할 수 있습니다.

즉, @RequestMapping(value = "/cmm/cmmPlayer.do") 대신 @RequestMapping("/cmm/cmmPlayer.do")처럼 사용할 수 있습니다. (annotation 변수명이 value인 값만 가능)

 

그렇다면 세부적으로 어떻게 동작할까요?

 

@RequestMapping annotation 구조

위 소스는 직접 @RequestMapping 어노테이션을 타고 들어가서 본 내용입니다. 이젠 익숙한 내용들이 보일 것 입니다.

 

@Target({ElementType.METHOD, ElementType.TYPE})

해당 annotation은 매서드와 클래스, 인터페이스, enum에서 사용하도록 Target을 설정하겠다는 의미입니다.

 

@Retention(RetentionPolicy.RUNTIME)

해당 어노테이션을 런타임 시점에서 실행시키겠다는 의미입니다.

 

 

@RequestMapping annotation 구조-2

@RequestMapping의 핵심 요소인 String value() default { };RequestMethod[] method() defalut { };를 확인할 수 있습니다. value에 Mapping할 주소를 넣어주면 런타임 시점에 해당 주소와 URI는 서로 연결되게 됩니다.

 

또한, Request방식을 설정할 때 method = RequestMethod.GET 과 같이 GET호출 POST호출 등을 설정할 수 있습니다.

자료형인 RequestMethod[]를 확인해보면 GET, POST, PUT, PATCH 등과 같이 다양한 옵션이 enum으로 설정되어 있습니다.

 

RequestMethod enum 내부구조

 

이제 어느정도 Annotation의 구조가 눈에 파악될 것 입니다. 하지만, 더 깊은 세부 로직까지 아직은 알 필요가 없다고 생각하여 이정도로 정리하겠습니다.

 

※ 잘못된 내용이 있거나, 설명이 불충분한 부분이 있다면 답변 부탁드립니다.

 

 

Reference

 

 

+ Recent posts