๐Ÿ’ป ๊ณต๋ถ€ ๊ธฐ๋ก/๐Ÿƒ Spring

Spring | Reflection์„ ์‚ฌ์šฉํ•˜์—ฌ Annotation ๊ฐ€์ ธ์˜ค๊ธฐ

  • -
ํ•ด๋‹น ๋‚ด์šฉ์€ ๊ณต๋ถ€์˜ ๋ชฉ์ ์œผ๋กœ ๊ธฐ๋ก๋˜์—ˆ์œผ๋ฉฐ,
์•„๋ž˜ ๋‚ด์šฉ์€ ๋ชจ๋‘ ๊ตฌ๊ธ€ ๊ฒ€์ƒ‰์œผ๋กœ ๊ณต๋ถ€ ๋ธ”๋กœ๊ทธ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.
์—ด์‹ฌํžˆ ๋ฐฐ์šฐ๋Š” ์ค‘์ž…๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

 

 


 

 

๐Ÿ“Œ ๋ฆฌํ”Œ๋ ‰์…˜ (Reflection)

๋ฆฌํ”Œ๋ ‰์…˜์€ ์ƒ์„ฑ์ž, ๋ฉ”์†Œ๋“œ, ํ•„๋“œ ๋“ฑ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์•„์ฃผ ์ž์„ธํžˆ ์•Œ๋ ค์ฃผ๋Š” ์ž๋ฐ” API ์ด๋‹ค.
๋Œ€ํ‘œ์ ์ธ ์˜ˆ์‹œ๋กœ ์—ฌ๋Ÿฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ฆฌํ”Œ๋ ‰์…˜์„ ํ†ตํ•ด ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ• ๋“ฑ์ด ์žˆ๋‹ค.
๋ฆฌํ”Œ๋ ‰์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ์ ‘๊ทผ ์ œ์–ด์ž์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ํด๋ž˜์Šค์˜ ํ•„๋“œ๋‚˜ ๋ฉ”์†Œ๋“œ๋„ ๊ฐ€์ ธ์™€์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿ“Œ ์–ด๋…ธํ…Œ์ด์…˜ (Annotation) ๊ฐ€์ ธ์˜ค๊ธฐ

๋Œ€ํ‘œ์ ์ธ ์˜ˆ์‹œ ์ค‘ ํ•˜๋‚˜๋ฅผ ์‹ค์Šตํ•ด๋ดค๋‹ค.

 

๐Ÿ“Œ ์ž„์˜ ์–ด๋…ธํ…Œ์ด์…˜ ์ƒ์„ฑ

 

์–ด๋…ธํ…Œ์ด์…˜์˜ ํด๋” ๊ตฌ์„ฑ

Controller, RequestMapping, Service ๋ฅผ ์ƒ์„ฑ

 

์ž„์˜ ์–ด๋…ธํ…Œ์ด์…˜์˜ ์ฝ”๋“œ

package com.example.mvcpractice.annotation;

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

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
}

 

 

๐Ÿ“Œ ์–ด๋…ธํ…Œ์ด์…˜ ์„ ์–ธ์ฝ”๋“œ

๋”๋ณด๊ธฐ

์–ด๋…ธํ…Œ์ด์…˜์„ ์„ ์–ธํ•˜๊ธฐ ์œ„ํ•œ ์ฝ”๋“œ๋กœ @Target ์ด๋ผ๋Š” ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค. ํ•ด๋‹น ์‚ฌ์šฉ์ž๊ฐ€ ๋งŒ๋“  ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ€์ฐฉ๋  ์ˆ˜ ์žˆ๋Š” ํƒ€์ž…์„ ์ง€์ •ํ•œ๋‹ค. (ํƒ€์ž…: ํด๋ž˜์Šค, ์ƒ์„ฑ์ž, ๋ฉ”์„œ๋“œ ๋“ฑ๋“ฑ)

 

์–ด๋…ธํ…Œ์ด์…˜ ์„ ์–ธ์ฝ”๋“œ ๊ตฌ์„ฑ

์‚ฌ์šฉ์ž ์ƒ์„ฑ: @Controller

import java.lang.annotation.ElementType;

@Target({ElementType.TYPE})
// TYPE ์ด์™ธ์—๋„ CONSTRUCTOR, METHOD, FIELD ๊ฐ€ ์žˆ์œผ๋ฉฐ, ์›ํ•˜๋Š” ํƒ€์ž…์„ ์ž‘์„ฑํ•œ๋‹ค.
public @interface Controller {
}

 

@Retention์€ ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์ด ์–ธ์ œ๊นŒ์ง€ ์œ ์ง€ํ• ์ง€ ์•Œ๋ ค์ฃผ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค.

์–ด๋…ธํ…Œ์ด์…˜์„ ์„ ์–ธํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ์ž์˜ ์ƒ์„ฑ ์–ด๋…ธํ…Œ์ด์…˜ ๋˜ํ•œ ์–ด๋Š ์‹œ์ ๊นŒ์ง€ ์œ ํšจํ•œ์ง€๋ฅผ ๋ช…์‹œํ•ด์ค˜์•ผ ํ•œ๋‹ค.

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

@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
}

 

@Retention์— ์‚ฌ์šฉํ•˜๋Š” RetentionPolicy๋Š” SOURCE, CLASS, RUNTIME ์ด๋ ‡๊ฒŒ 3๊ฐ€์ง€ ์†์„ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. 

* SOURCE

- ์ปค์Šคํ…€ํ•œ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ฃผ์„์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

- ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์ปดํŒŒ์ผ ํ›„ ์ƒ์„ฑ๋œ .class ์— ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜ ์ •๋ณด๊ฐ€ ์‚ฌ๋ผ์ง€๊ณ  ์†Œ์Šค์ฝ”๋“œ๊นŒ์ง€๋งŒ ์œ ์ง€ํ•œ๋‹ค.

- ์ปดํŒŒ์ผ ํ›„ ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์€ ์‚ฌ๋ผ์ง„๋‹ค.

 

* CLASS

- @Retention์˜ ๊ธฐ๋ณธ๊ฐ’ ํด๋ž˜์Šค ํƒ€์ž…์ด๋‹ค.

- ๋Ÿฐํƒ€์ž„ ์‹œ ํด๋ž˜์Šค๋ฅผ ๋ฉ”๋ชจ๋ฆฌ๋กœ ์ฝ์–ด์˜ค๋ฉด ํ•ด๋‹น ์ •๋ณด๋Š” ์‚ฌ๋ผ์ง„๋‹ค.

 

* RUNTIME

- ํด๋ž˜์Šค๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์ฝ์–ด์™”์„ ๋•Œ๊นŒ์ง€ ์œ ์ง€ํ•œ๋‹ค.

- ์ฝ”๋“œ์—์„œ ์ด ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ํŠน์ • ๋กœ์ง์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿ“Œ ์–ด๋…ธํ…Œ์ด์…˜ ๋ถ€์ฐฉ ํด๋ž˜์Šค ์ƒ์„ฑ

 

HomeController.class

 

์ƒ์„ฑํ•œ ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ€์ฐฉํ•  ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

package com.example.mvcpractice.controller;

import com.example.mvcpractice.annotation.Controller;
// ํ•ด๋‹น ํŒจํ‚ค์ง€๋ฅผ ํ™•์ธํ•˜๋ฉด ์‚ฌ์šฉ์ž ์ƒ์„ฑ ์–ด๋…ธํ…Œ์ด์…˜์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
import com.example.mvcpractice.annotation.RequestMapping;
import com.example.mvcpractice.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller // ์‚ฌ์šฉ์ž ์ƒ์„ฑ ์–ด๋…ธํ…Œ์ด์…˜
public class HomeController {

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(HttpServletRequest request, HttpServletResponse response) {
        return "home";
    }
}

 

๐Ÿ“Œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

 

ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค ์ƒ์„ฑ

ReflectionTest.class

 

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

package com.example.mvcpractice;

import com.example.mvcpractice.annotation.Controller;
import com.example.mvcpractice.annotation.Service;
import org.junit.jupiter.api.Test;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class ReflectionTest {
    private static final Logger logger = LoggerFactory.getLogger(ReflectionTest.class);
    // ์‚ฌ์šฉ์ž๊ฐ€ ์ƒ์„ฑํ•œ ์–ด๋…ธํ…Œ์ด์…˜์„ ๋กœ๊ทธ๋กœ ํ™•์ธํ•œ๋‹ค.

    @Test
    void controllerScan() {
        Set<Class<?>> beans = getTypesAnnotatedWith(List.of(Controller.class, Service.class));

        logger.info("beans: [{}]", beans);
        // beans ์— ๋‹ด๊ธด ๋‚ด์šฉ์„ ๋กœ๊ทธ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
    }

    // getTypesAnnotatedWith() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด Controller๊ณผ Service ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ€์ฐฉ๋œ ํด๋ž˜์Šค๋ฅผ ์ฐพ๋Š”๋‹ค.
    private static Set<Class<?>> getTypesAnnotatedWith(List<Class<? extends Annotation>> annotations) {
        Reflections reflections = new Reflections("com.example.mvcpractice");
        // reflection ์˜ ํ•ด๋‹น ํŒจํ‚ค์ง€ ๋ฐ‘์— ์žˆ๋Š” ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

        Set<Class<?>> beans = new HashSet<>();
        annotations.forEach(annotation -> beans.addAll(reflections.getTypesAnnotatedWith(annotation)));
        // reflections.getTypesAnnotatedWith() ์˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ํด๋ž˜์Šค๊ฐ€ ์œ„์น˜ํ•œ ํŒจํ‚ค์ง€ ์ •๋ณด๋ฅผ ๋‹ด๋Š”๋‹ค.

        return beans;
    }
}

 

์‹คํ–‰ ๊ฒฐ๊ณผ

์–ด๋…ธํ…Œ์ด์…˜ Controller์™€ Service ๊ฐ€ ๋ถ€์ฐฉ๋œ ํด๋ž˜์Šค ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์™”๋‹ค.

 

 

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ2

    @Test
    void showClass() {
        Class<User> clazz = User.class;
        logger.info(clazz.getName());

        logger.info("User all declarde fields [{}]", Arrays.stream(clazz.getDeclaredFields()).collect(Collectors.toList()));
        // getDeclaredFields(): User ํด๋ž˜์Šค์— ์„ ์–ธ๋œ ๋ชจ๋“  ํ•„๋“œ(String userId, String name)๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
        logger.info("User all declarde constructors [{}]", Arrays.stream(clazz.getDeclaredConstructors()).collect(Collectors.toList()));
        // getDeclaredConstructors(): User ํด๋ž˜์Šค์— ์„ ์–ธ ๋˜์–ด์žˆ๋Š” ๋ชจ๋“  ์ƒ์„ฑ์ž(User(...))๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
        logger.info("User all declarde Methods [{}]", Arrays.stream(clazz.getDeclaredMethods()).collect(Collectors.toList()));
        // getDeclaredMethods(): User ํด๋ž˜์Šค์— ์„ ์–ธ๋œ ๋ฉ”์†Œ๋“œ(equalsUser(...))๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
    }

 

์‹คํ–‰ ๊ฒฐ๊ณผ

 

๐Ÿ“Œ ๋์œผ๋กœ

Reflection์„ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ์ž์ฃผ ๋“ฑ์žฅํ•˜๋Š” ๋ง์ด ์žˆ๋Š”๋ฐ '๊ตณ์ด ์•Œ์•„์•ผํ• ๊นŒ?', 'ํ™œ์šฉํ•  ์ผ์ด ๊ฑฐ์˜ ์—†๋‹ค' ๋“ฑ์ด๋‹ค.

์ƒ๊ฐ์ฒ˜๋Ÿผ ์ •๋ณด๋ฅผ ํ™•์ธํ•˜๋Š” ๊ธฐ๋Šฅ์ด์ง€๋งŒ, ํ”ํžˆ ์‚ฌ์šฉํ•˜๊ฒŒ ๋  ๊ตฌ์ฒด์ ์ธ ํด๋ž˜์Šค๋ฅผ ๋ชจ๋ฅผ๋ฆฌ ์—†์–ด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋“ฏ ํ•˜๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋‹จ์ ์œผ๋กœ ์•Œ๋ ค์ง„ ๋‚ด์šฉ๋“ค ์ค‘, ์„ฑ๋Šฅ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์žˆ๋‹ค.

์ปดํŒŒ์ผ ํƒ€์ž„์ด ์•„๋‹Œ ๋Ÿฐํƒ€์ž„์— ๋™์ ์œผ๋กœ ํƒ€์ž…์„ ๋ถ„์„ํ•˜๊ณ  ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋ฏ€๋กœ JVM์„ ์ตœ์ ํ™” ํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ํ•œ๋‹ค.

(์•„์ง ๋ฌด์Šจ ์†Œ๋ฆฌ์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ, ์•ˆ์ข‹์€ ๊ฒƒ ๊ฐ™๋‹ค.)

๋‹จ์ ์ด๋ผ ๋งํ•˜๊ณ  ์˜ˆ์ƒ๋ชปํ•  ๋ถ€์ž‘์šฉ์„ ๊ตณ์ด ๊ฐ์ˆ˜ํ•  ํ•„์š”๋Š” ์—†๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•˜์ง€ ๋ง์ž๋Š” ๊ฒฐ๋ก ์— ๋„๋‹ฌํ–ˆ๋‹ค.

 

์ฐพ์œผ๋ฉด์„œ ๋ฐฐ์šด ์–ด๋…ธํ…Œ์ด์…˜์˜ ์„ ์–ธ์ฝ”๋“œ๋„ ์•Œ๊ฒŒ๋˜์—ˆ๋‹ค.์•„์ง๊นŒ์ง€ ์ง์ ‘์ ์œผ๋กœ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ƒ์„ฑํ•˜๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ๊นŒ์ง€ ์‹ค๋ ฅ์ด ๋ถ€์กฑํ•˜์ง€๋งŒ, ์ข‹์€ ๊ณต๋ถ€๊ฐ€ ๋˜์—ˆ๋‹ค.

 

 

 

์ถœ์ฒ˜ | hudi

 

์ž๋ฐ” ๋ฆฌํ”Œ๋ ‰์…˜ (Reflection) ๊ธฐ์ดˆ

๋ฆฌํ”Œ๋ ‰์…˜ (Reflection) JVM์€ ํด๋ž˜์Šค ์ •๋ณด๋ฅผ ํด๋ž˜์Šค ๋กœ๋”๋ฅผ ํ†ตํ•ด ์ฝ์–ด์™€์„œ ํ•ด๋‹น ์ •๋ณด๋ฅผ JVM ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•œ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ์ €์žฅ๋œ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ๋งˆ์น˜ ๊ฑฐ์šธ์— ํˆฌ์˜๋œ ๋ชจ์Šต๊ณผ ๋‹ฎ์•„์žˆ์–ด, ๋ฆฌํ”Œ๋ ‰์…˜

hudi.blog

์ถœ์ฒ˜ | goodGid

 

Spring MVC - @Retention ์• ๋…ธํ…Œ์ด์…˜

Index

goodgid.github.io

์ถœ์ฒ˜ | Tecoble

 

Reflection API ๊ฐ„๋‹จํžˆ ์•Œ์•„๋ณด์ž.

Spring Framework๋ฅผ ํ•™์Šตํ•˜๋‹ค ๋ณด๋ฉด Java Reflection API๋ฅผ ์ž์ฃผ ์ ‘ํ•˜๊ฒŒ ๋œ๋‹ค. ํ•˜์ง€๋งŒ Reflection API…

tecoble.techcourse.co.kr

 

Contents

ํฌ์ŠคํŒ… ์ฃผ์†Œ๋ฅผ ๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค

์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด ๊ณต๊ฐ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.