어노테이션(Annotation)

JiwonMoon·2022년 1월 18일
0

Spring

목록 보기
3/10
post-thumbnail

어노테이션(Annotation) 이란?

Annotation를 해석하면 주석이라는 뜻이다.
자바에서 Annotation은 코드 사이에 주석과 같은 형태로 쓰이며, 특별한 의미, 기능을 수행하도록 하는 기술이다.
즉, 프로그램에게 추가적인 정보를 제공해주는 메타데이터라고 볼 수 있다.
(meta data : 데이터를 위한 데이터)
메타데이터란 애플리케이션이 처리해야할 데이터가 아니라, 컴파일 과정과 실행과정에서 코드를 어떻게 컴파일하고 처리할 것 인지 알려주는 정보이다.

Annotation의 용도

  1. 컴파일러에게 코드 작성 문법 에러를 체크하도록 정보를 제공한다.
  2. SW 개발 툴이 빌드나 배치시 코드를 자동으로 생성할 수 있는 정보를 제공한다.
  3. 실행시(런타임 시) 특정기능을 실행하도록 정보를 제공한다.

순서
1. Annotation을 정의한다.
2. 클래스에 Annotation을 배치한다.
3. 코드가 실행되는 중에 Reflection을 이용하여 추가 정보를 획득하여 기능을 실시한다.

Reflection 이란?

Reflection이란 프로그램이 실행 중에 자신의 구조와 동작을 검사하고, 조사하고, 수정하는 것이다.
구체적인 클래스 타입을 알지 못해도 그 클래스의 메소드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API

Reflection은 프로그래머가 데이터를 보여주고, 다른 포맷의 데이터를 처리하고, 통신을 위해 serialization(직렬화)를 수행하고, bundling을 하기 위해 일반 소프트웨어 라이브러리를 만들도록 도와준다.

Java와 같은 객체 지향 프로그래밍 언어에서 Reflection을 사용하면 컴파일 타임에 인터페이스, 필드, 메소드의 이름을 알지 못해도 실행 중에 클래스, 인터페이스, 필드 및 메소드에 접근할 수 있다.

또한 새로운 객체의 인스턴스화 및 메소드 호출을 허용한다.

Java와 같은 객체 지향 프로그래밍 언어에서 Reflection을 사용하여 멤버 접근 가능성 규칙을 무시할 수 있다.

Spring에서 BeanFactory라는 Container에서 객체가 호출되면 객체의 인스턴스를 생성하게 되는데 이 때 필요하게 된다.

즉, 프레임워크에서 유연성있는 동작을 위해 쓰인다.

Annotation 자체는 아무런 동작을 가지지 않는 단순한 표식일 뿐이지만, Reflection을 이용하면 Annotation의 적용 여부와 엘리먼트 값을 읽고 처리할 수 있다.

Class에 적용된 Annotation 정보를 읽으려면 java.lang.Class를 이용하고
필드, 생성자, 메소드에 적용된 어노테이션 정보를 읽으려면 Class의 메소드를 통해 java.lang.reflect 패키지의 배열을 얻어야 한다.

Class.forName(), getName(), getModifier(), getFields() getPackage() 등등 여러 메소드로 정보를 얻을 수 있다.

Reflection을 이용하면 Annotation 지정만으로도 원하는 클래스를 주입할 수 있다.

Annotation 종류

1. @ComponentScan

@Component와 @Service, @Repository, @Controller, @Configuration이 붙은 클래스 Bean들을 찾아서 Context에 bean등록을 해주는 Annotation이다.
@Component Annotation이 있는 클래스에 대하여 bean 인스턴스를 생성

ApplicationContext.xml에 과 같이 xml에 bean을 직접적으로 등록하는 방법도 있고,
위와 같이 Annotation @을 붙여서 사용하는 방법도 있다.

base-package를 넣으면 해당 패키지 아래에 있는 컴포넌트들을 찾고 그 과정을 spring-context.jar에서 처리한다.

Spring에서는 @Component로 전부 사용하지 않고 @Repository, @Service, @Controller등을 사용하는 이유는, @Repository는 DAO의 메소드에서 발생할 수 있는 unchecked exception들을 스프링의 DataAccessException으로 처리할 수 있기 때문이다.

또한 가독성에서도 해당 애노테이션을 갖는 클래스가 무엇을 하는지 단 번에 알 수 있다.

자동으로 등록되는 Bean의 이름은 클래스의 첫문자가 소문자로 바뀐 이름이 자동적용된다.
UserController -> userController

2. @Component

@Component 은 개발자가 직접 작성한 Class를 Bean으로 등록하기 위한 Annotation이다.

@Component
public class User {
    public User() {
   		// ~~
    }
}

@Component(value="myuser")
public class User {
    public User() {
   		// ~~
    }
}

Component에 대한 추가 정보가 없다면 Class의 이름을 camelCase로 변경한 것이 Bean id로 사용된다.
하지만 @Bean과 다르게 @Component는 name이 아닌 value를 이용해 Bean의 이름을 지정한다.

3. @Bean

@Bean은 개발자가 직접 제어가 불가능한 외부 라이브러리등을 Bean으로 만들려할 때 사용되는 Annotation이다.

@Configuration
public class ApplicationConfig {    
    @Bean
    public ArrayList<String> array(){
        return new ArrayList<String>();
    }   
}

ArrayList같은 라이브러리등을 Bean으로 등록하기 위해서는 별도로 해당 라이브러리 객체를 반환하는 Method를 만들고 @Bean Annotation을 사용하면 된다.

위의 경우 @Bean에 아무런 값을 지정하지 않았으므로 Method 이름을 camelCase로 변경한 것이 Bean id로 등록된다.
method 이름이 arrayList()인 경우 arrayList가 Bean id

@Configuration
public class ApplicationConfig {    
    @Bean(name="myarray")
    public ArrayList<String> array(){
        return new ArrayList<String>();
    }   
}

위와 같이 @Bean에 name이라는 값을 이용하면 자신이 원하는 id로 Bean을 등록할 수 있다.

4. @Autowired

속성(field), setter method, constructor(생성자)에서 사용하며 Type에 따라 알아서 Bean을 주입 해준다.
무조건적인 객체에 대한 의존성을 주입시킨다.
이 Annotation을 사용할 시, 스프링이 자동적으로 값을 할당한다.
Controller 클래스에서 DAO나 Service에 관한 객체들을 주입 시킬 때 많이 사용한다.

필드, 생성자, 입력 파라미터가 여러 개인 메소드(@Qualifier는 메소드의 파라미터)에 적용 가능하다.

Type을 먼저 확인한 후 못 찾으면 Name에 따라 주입한다.
Name으로 강제하는 방법: @Qualifier을 같이 명시

Bean을 주입받는 방식 (3가지)
1. @Autowired
2. setter
3. 생성자 (@AllArgsConstructor 사용) // 권장방식

5. @Inject

@Autowired 어노테이션과 비슷한 역할을 한다.

@Autowired와 @Inject의 차이점
두가지의 어노테이션은 동일하게 작동하지만 찾는 순서가 다르다.
@Autowired 경우

타입 -> 이름 -> @Qualifier -> 실패

@Inject 경우

타입 -> @Qualifier-> 이름 -> 실패

6. @Controller

Spring의 Controller를 의미한다. Spring MVC에서 Controller클래스에 쓰인다.

7. @RestController

Spring에서 Controller 중 View로 응답하지 않는, Controller를 의미한다.

method의 반환 결과를 JSON 형태로 반환한다.

이 Annotation이 적혀있는 Controller의 method는 HttpResponse로 바로 응답이 가능하다.
@ResponseBody 역할을 자동적으로 해주는 Annotation이다.
@Controller + @ResponseBody를 사용하면 @ResponseBody를 모든 메소드에서 적용한다.

@Controller 와 @RestController 의 차이
@Controller
API와 view를 동시에 사용하는 경우에 사용한다.
대신 API 서비스로 사용하는 경우는 @ResponseBody를 사용하여 객체를 반환한다.
view(화면) return이 주목적이다.

@RestController
view가 필요없는 API만 지원하는 서비스에서 사용한다.
Spring 4.0.1부터 제공
@RequestMapping 메서드가 기본적으로 @ResponseBody 의미를 가정한다.
data(json, xml 등) return이 주목적이다.

즉, @RestController = @Controller + @ResponseBody 이다.

8. @Service

Service Class에서 쓰인다.
비즈니스 로직을 수행하는 Class라는 것을 나타내는 용도이다.

9. @Repository

DAO class에서 쓰인다.
DataBase에 접근하는 method를 가지고 있는 Class에서 쓰인다.

10. @EnableAutoConfiguration

Spring Application Context를 만들 때 자동으로 설정하는 기능을 켠다.

classpath의 내용에 기반해서 자동으로 생성해준다.

만약 tomcat-embed-core.jar가 존재하면 톰캣 서버가 setting된다.

11. @Configuration

@Configuration을 클래스에 적용하고 @Bean을 해당 Class의 method에 적용하면,
@Autowired로 Bean을 부를 수 있다.

12. @Required

setter method에 적용해주면 Bean 생성시 필수 프로퍼티 임을 알린다.
Required Annotation을 사용하여 optional 하지 않은, 꼭 필요한 속성들을 정의한다.
영향을 받는 bean property를 구성할 시에는 XML 설정 파일에 반드시 property를 채워야 한다.

<bean id = "student" class = "com.tutorialspoint.Student">
    <property name = "name" value = "Moon" />
    <property name = "age"  value = "25"/>
</bean>

13. @Qualifier("id123")

@Autowired와 같이 쓰이며, 같은 타입의 Bean 객체가 있을 때 해당 아이디를 적어 원하는 Bean이 주입될 수 있도록 하는 Annotation이다.
같은 타입의 Bean이 두 개 이상이 존재하는 경우에 Spring이 어떤 Bean을 주입해야 할지 알 수 없어서 Spring Container를 초기화하는 과정에서 예외를 발생시킨다.
이 경우 @Qualifier을 @Autowired와 함께 사용하여 정확히 어떤 bean을 사용할지 지정하여 특정 의존 객체를 주입할 수 있도록 한다.

14. @Resource

@Autowired와 마찬가지로 Bean 객체를 주입해주는데 차이점은 Autowired는 타입으로, Resource는 이름으로 연결해준다.
Annotation 사용으로 인해 특정 Framework에 종속적인 어플리케이션을 구성하지 않기 위해서는 @Resource를 사용할 것을 권장한다.
@Resource를 사용하기 위해서는 class path 내에 jsr250-api.jar 파일을 추가해야 하고,
필드, 입력 파라미터가 한 개인 bean property setter method에 적용 가능하다.

15. @PostConstruct, @PreConstruct

의존하는 객체를 생성한 이후 초기화 작업을 위해 객체 생성 전/후에(pre/post) 실행해야 할 method 앞에 붙인다.

16. @PreDestroy

객체를 제거하기 전(pre)에 해야할 작업을 수행하기 위해 사용한다.

17. @PropertySource

해당 프로퍼티 파일을 Environment로 로딩하게 해준다.

클래스에 @PropertySource("classpath:/settings.properties")라고 적고 클래스 내부에 @Resource를 Environment타입의 멤버 변수앞에 적으면 매핑된다.

18. @ConfigurationProperties

yaml파일 읽는다.

default로 classpath:application.properties 파일이 조회된다.

속성 클래스를 따로 만들어두고 그 위에 (prefix="mail")을 써서 프로퍼티의 접두사를 사용할 수 있다.

19. @Lazy

지연로딩을 지원한다.

@Component나 @Bean Annotation과 같이 쓰는데 Class가 로드될 때 스프링에서 바로 bean등록을 마치는 것이 아니라 실제로 사용될 때 로딩이 이뤄지게 하는 방법이다.

20. @SpringBootApplication

@Configuration, @EnableAutoConfiguration, @ComponentScan 3가지를 하나의 애노테이션으로 합친 것이다.

21. @RequestMapping

요청 URL을 어떤 method가 처리할지 mapping해주는 Annotation이다.

Controller나 Controller의 method에 적용한다.

요청을 받는 형식인 GET, POST, PATCH, PUT, DELETE 를 정의하기도 한다.

요청 받는 형식을 정의하지 않는다면, 자동적으로 GET으로 설정된다.

@RequestMapping("/list"), @RequestMapping("/home, /about");
@RequestMapping("/admin", method=RequestMethod.GET)
@Controller
// 1) Class Level
//모든 메서드에 적용되는 경우 “/home”로 들어오는 모든 요청에 대한 처리를 해당 클래스에서 한다는 것을 의미
@RequestMapping("/home") 
public class HomeController {
    /* an HTTP GET for /home */ 
    @RequestMapping(method = RequestMethod.GET)
    public String getAllEmployees(Model model) {
        ...
    }
    /*
    2) Handler Level
    요청 url에 대해 해당 메서드에서 처리해야 되는 경우
    “/home/employees” POST 요청에 대한 처리를 addEmployee()에서 한다는 것을 의미한다.
    value: 해당 url로 요청이 들어오면 이 메서드가 수행된다.
    method: 요청 method를 명시한다. 없으면 모든 http method 형식에 대해 수행된다.
    */
    /* an HTTP POST for /home/employees */ 
    @RequestMapping(value = "/employees", method = RequestMethod.POST) 
    public String addEmployee(Employee employee) {
        ...
    }
}

@RequestMapping에 대한 모든 매핑 정보는 Spring에서 제공하는 HandlerMapping Class가 가지고 있다.

22. @CookieValue

쿠키 값을 parameter로 전달 받을 수 있는 방법이다.

해당 쿠키가 존재하지 않으면 500 에러를 발생시킨다.

속성으로 required가 있는데 default는 true다.
false를 적용하면 해당 쿠키 값이 없을 때 null로 받고 에러를 발생시키지 않는다.

// 쿠키의 key가 auth에 해당하는 값을 가져옴
public String view(@CookieValue(value="auth")String auth){...}; 

23. @CrossOrigin

CORS 보안상의 문제로 브라우저에서 리소스를 현재 origin에서 다른 곳으로의 ajax요청을 방지하는 것이다.
CORS란?

  • Cross-Origin Resource Sharing (CORS)
    많은 웹 어플리케이션들이 이미지 파일이나 폰트, css 파일 같은 리소스들을 각각의 출처로부터 읽어온다. 만약에 웹 어플리케이션이 자기 자신이 속하지 않은 다른 도메인, 다른 프로토콜, 혹은 다른 포트에 있는 리소스를 요청하면 웹 어플리케이션은 cross-origin HTTP 요청을 실행한다. 만약에 프론트엔드 자바스크립트 코드가 https://domain-a.com에서 https://domain-b.com/data.json으로 json 데이터 요청을 보낸다면 이것이 바로 cross-origin HTTP 요청이 된다.

@RequestMapping이 있는 곳에 사용하면 해당 요청은 타 도메인에서 온 ajax요청을 처리해준다.

/기본 도메인이 http://jeong-pro.tistory.com 인 곳에서 온 ajax요청만 받아주겠다.
@CrossOrigin(origins = "http://jeong-pro.tistory.com", maxAge = 3600)

24. @ModelAttribute

iew에서 전달해주는 parameter를 Class(VO/DTO)의 멤버 변수로 binding 해주는 Annotation이다.

binding 기준은

<input name="id"/>

처럼 어떤 태그의 name값이 해당 Class의 멤버 변수명과 일치해야하고 setmethod명도 일치해야한다.

class Person{

String id;

public void setId(String id){ this.id = id;}
public String getId(){ return this.id }
}

@Controller
@RequestMapping("/person/*")
public class PersonController{
	@RequestMapping(value = "/info", method=RequestMethod.GET)
    	//view에서 myMEM으로 던져준 데이터에 담긴 id 변수를 Person타입의 person이라는 객체명으로 바인딩.
	public void show(@ModelAttribute("myMEM") Person person, Model model)
	{ model.addAttribute(service.read(person.getId())); }
}

25. @GetMapping

@RequestMapping(Method=RequestMethod.GET)과 같다.
@PostMapping, @PutMapping, @PatchMapping, @DeleteMapping 등 도 있다.

26. @SessionAttributes

Session에 data를 넣을 때 쓰는 Annotation이다.

@SessionAttributes("name")이라고 하면 Model에 key값이 "name"으로 있는 값은 자동으로 세션에도 저장되게 한다.

27. @Valid

유효성 검증이 필요한 객체임을 지정한다.

28. @InitBinder

@Valid 애노테이션으로 유효성 검증이 필요하다고 한 객체를 가져오기전에 수행해야할 method를 지정한다.

29. @RequestAttribute

Request에 설정되어 있는 속성 값을 가져올 수 있다.

30. @RequestBody

요청이 온 데이터(JSON이나 XML형식)를 바로 Class나 model로 매핑하기 위한 Annotation이다.

POST나 PUT, PATCH로 요청을 받을때에, 요청에서 넘어온 body 값들을 자바 타입으로 파싱해준다.

HTTP POST 요청에 대해 request body에 있는 request message에서 값을 얻어와 매핑한다.
RequestData를 바로 Model이나 클래스로 매핑한다.

이를테면 JSON 이나 XML같은 데이터를 적절한 messageConverter로 읽을 때 사용하거나 POJO 형태의 데이터 전체로 받는 경우에 사용한다.

@RequestMapping(value = "/book", method = RequestMethod.POST)
public ResponseEntity<?> someMethod(@RequestBody Book book) {
// we can use the variable named book which has Book model type.
try {
   service.insertBook(book);
} catch(Exception e) {
    e.printStackTrace();
}

// return some response here
}

31. @Value

properties에서 값을 가져와 적용할 때 사용한다.

@Value("${value.from.file}")

private String valueFromFile; 이라고 구성되어 있으면 value.from.file의 값을 가져와서 해당 변수에 주입해준다.

References (참고 자료)

0개의 댓글