Reflection

ํ•ธ๋“ค๋Ÿฌ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์›๋ฆฌ ์ดํ•ด

์‚ฌ์ „ ์ง€์‹ : ๋ฆฌํ”Œ๋ ‰์…˜

  • ์Šคํ”„๋ง์˜ ํ•ธ๋“ค๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ํด๋ž˜์Šค๋Š” InvocableHandlerMethod์™€ ์ด๋ฅผ ํ™•์žฅํ•œ ServletInvocableHandlerMethod ํด๋ž˜์Šค๊ฐ€ ์žˆ๋‹ค.

  • ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ ๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ•ด์„ํ•˜๊ธฐ ์œ„ํ•œ HandlerMethodArgumentResolver์™€ ๋ฉ”์„œ๋“œ ๋ฐ˜ํ™˜ ๊ฐ’์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ HandlerMethodReturnValueHandler์™€ ๊ฐ™์€ ํด๋ž˜์Šค์™€ ์—ฐ๊ณ„ํ•˜์—ฌ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

  • InvocableHandlerMethod๋Š” ๋ฒ”์šฉ์  ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ํด๋ž˜์Šค์ด๋ฉฐ, ServletInvocableHandlerMethod HTTP ์š”์ฒญ ๋ฐ ์‘๋‹ต ์ฒ˜๋ฆฌ ํด๋ž˜์Šค๋กœ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋‹ค.

img.png

InvocableHandlerMethod

  • HTTP ํ”„๋กœํ† ์ฝœ์— ๋…๋ฆฝ์ ์ด๋ฉฐ ๋ฒ”์šฉ์ ์ธ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ณ  ๋งค๊ฐœ๋ณ€์ˆ˜ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด HandlerMethodArgumentResolver๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

  • ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฐ˜ํ™˜๊ฐ’์„ ์ถ”๊ฐ€๋กœ ์ฒ˜๋ฆฌํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค.

img_2.png

InvocableHandlerMethod ์‚ฌ์šฉ ์˜ˆ์ œ

/*--------------------Service--------------------*/
@Service
public class MyService {
    public String processRequest(User user) {
        return "Hello from MyService, " + user.getUsername() + ": " + user.getEmail();
    }
}

/*--------------------ArgumentResolver--------------------*/
public class MyArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().equals(User.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter,
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) {
        User user = new User();
        user.setUsername(webRequest.getParameter("username"));
        user.setEmail(webRequest.getParameter("email"));

        return user;
    }
}

/*--------------------Controller--------------------*/
@Controller
@RequiredArgsConstructor
public class MyController {

    private final MyService myService;

    @GetMapping("/invokeService1")
    public void invokeService1(HttpServletRequest request, HttpServletResponse response) throws Exception {

        //Service ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ด
        Method serviceMethod = myService.getClass().getMethod("processRequest", User.class);

        //InvocableHandlerMethod ์ƒ์„ฑ
        InvocableHandlerMethod invocableHandlerMethod = new InvocableHandlerMethod(myService, serviceMethod);

        //Service ๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ ํ•ด์„์„ ์œ„ํ•ด ArgumentResolver ์„ค์ •
        HandlerMethodArgumentResolverComposite resolver = new HandlerMethodArgumentResolverComposite();
        resolver.addResolvers(new MyArgumentResolver());
        invocableHandlerMethod.setHandlerMethodArgumentResolvers(resolver);

        //์š”์ฒญ ์ฒ˜๋ฆฌ ๊ฐ์ฒด ์ƒ์„ฑ
        ServletWebRequest servletWebRequest = new ServletWebRequest(request, response);

        //๋ชจ๋ธ ๋ฐ์ดํ„ฐ ์ €์žฅ์„ ์œ„ํ•ด ํ•„์š”
        ModelAndViewContainer modelAndViewContainer = new ModelAndViewContainer();

        //๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ Service ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ
        Object result = invocableHandlerMethod.invokeForRequest(servletWebRequest, modelAndViewContainer);

        //๊ฒฐ๊ณผ๋ฅผ ์‘๋‹ต์œผ๋กœ ์ถœ๋ ฅ
        response.getWriter().write(result.toString());
    }
}

ServletInvocableHandlerMethod

  • InvocableHandlerMethod ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•œ ํด๋ž˜์Šค๋กœ Servlet ํ™˜๊ฒฝ(HttpServletRequest / HttpServletResponse)์— ํŠนํ™”๋˜์–ด ์žˆ์œผ๋ฉฐ HTTP ์š”์ฒญ ๋ฐ ์‘๋‹ต์„ ํฌํ•จํ•œ ํ•ธ๋“ค๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

  • ๋ฉ”์„œ๋“œ์˜ ๋ฐ˜ํ™˜ ๊ฐ’์„ HandlerMethodReturnValueHandler๋ฅผ ํ†ตํ•ด ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋ฉ”์„œ๋“œ ๋ ˆ๋ฒจ์˜ @ResponseStatus ์–ด๋…ธํ…Œ์ด์…˜์„ ์ง€์›ํ•˜์—ฌ HTTP ์‘๋‹ต ์ƒํƒœ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

img_1.png

ServletInvocableHandlerMethod ์‚ฌ์šฉ ์˜ˆ์ œ

/*--------------------Service--------------------*/
@Service
public class MyService {
    public String processRequest(User user) {
        return "Hello from MyService, " + user.getUsername() + ": " + user.getEmail();
    }
}

/*--------------------ArgumentResolver--------------------*/
public class MyArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().equals(User.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter,
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) {
        User user = new User();
        user.setUsername(webRequest.getParameter("username"));
        user.setEmail(webRequest.getParameter("email"));

        return user;
    }
}

/*--------------------ReturnValueHandler--------------------*/
public class MyReturnValueHandler implements HandlerMethodReturnValueHandler {

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return returnType.getParameterType().equals(String.class);
    }

    @Override
    public void handleReturnValue(Object returnValue,
                                  MethodParameter returnType,
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest) {
        if (returnValue != null) {
            mavContainer.addAttribute("result", returnValue);
        }
    }
}

/*--------------------Controller--------------------*/
@Controller
@RequiredArgsConstructor
public class MyController {

    private final MyService myService;

    @GetMapping("/invokeService2")
    public void invokeService2(HttpServletRequest request, HttpServletResponse response) throws Exception {

        //Service ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ด
        Method serviceMethod = myService.getClass().getMethod("processRequest", User.class);

        //ServletInvocableHandlerMethod ์ƒ์„ฑ
        ServletInvocableHandlerMethod invocableHandlerMethod = new ServletInvocableHandlerMethod(myService, serviceMethod);

        //Service ๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ ํ•ด์„์„ ์œ„ํ•ด ArgumentResolver ์„ค์ •
        HandlerMethodArgumentResolverComposite resolver = new HandlerMethodArgumentResolverComposite();
        resolver.addResolvers(new MyArgumentResolver());
        invocableHandlerMethod.setHandlerMethodArgumentResolvers(resolver);

        //Service ๋ฉ”์„œ๋“œ ๋ฐ˜ํ™˜๊ฐ’ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ReturnValueHandler ์„ค์ •
        HandlerMethodReturnValueHandlerComposite returnValueHandler = new HandlerMethodReturnValueHandlerComposite();
        returnValueHandler.addHandler(new MyReturnValueHandler());
        invocableHandlerMethod.setHandlerMethodReturnValueHandlers(returnValueHandler);

        //์š”์ฒญ ์ฒ˜๋ฆฌ ๊ฐ์ฒด ์ƒ์„ฑ
        ServletWebRequest servletWebRequest = new ServletWebRequest(request, response);

        //๋ชจ๋ธ ๋ฐ์ดํ„ฐ ์ €์žฅ์„ ์œ„ํ•ด ํ•„์š”
        ModelAndViewContainer modelAndViewContainer = new ModelAndViewContainer();

        //๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ Service ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ
        invocableHandlerMethod.invokeAndHandle(servletWebRequest, modelAndViewContainer);
        if (modelAndViewContainer.containsAttribute("result")) {
            //ModelAndViewContainer์— ์ €์žฅ๋œ ๊ฐ’์œผ๋กœ ์‘๋‹ต ์ž‘์„ฑ
            response.getWriter().write(modelAndViewContainer.getModel().get("result").toString());
        }
    }
}

๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ ์‹คํ–‰ ๊ตฌ์กฐ ์ดํ•ด

ํ•ต์‹ฌ ํด๋ž˜์Šค

  • ServletInvocableHandlerMethod

    • HTTP ์š”์ฒญ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„ ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚ค๋Š” ํด๋ž˜์Šค

    • HandlerMethodArgumentResolver๋ฅผ ํ†ตํ•ด ์š”์ฒญ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฉ”์„œ๋“œ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜์— ๋งž๊ฒŒ ๋ณ€ํ™˜ํ•˜๊ณ  ์ด๋ฅผ ์‚ฌ์šฉํ•ด ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

  • AnnotatedMethod

    • ํ˜ธ์ถœ ๋ฉ”์„œ๋“œ ๋ฐ ๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ ํŒŒ๋ผ๋ฏธํ„ฐ์— ์–ด๋…ธํ…Œ์ด์…˜ ์ •๋ณด๋ฅผ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • MethodParameter

    • ๋ฉ”์„œ๋“œ์— ์žˆ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํด๋ž˜์Šค

    • ๋ฉ”์„œ๋“œ์˜ ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ„์„ํ•˜๊ณ  ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์–ด๋””์— ์žˆ๊ณ  ์–ด๋–ค ํƒ€์ž…์ธ์ง€๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ์•Œ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.

  • MethodIntrospector

    • ๋ฉ”์„œ๋“œ๋ฅผ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํด๋ž˜์Šค

    • ์–ด๋…ธํ…Œ์ด์…˜์ด ์ ์šฉ๋œ ๋ฉ”์„œ๋“œ๋“ค์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ตฌํ•˜๊ฑฐ๋‚˜ ๋ฉ”์„œ๋“œ์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ฐพ๋„๋ก ๋„์™€์ค€๋‹ค.

img_3.png

MethodIntrospector

AnnotatedMethod & MethodParameter

์Šค์บ”ํ•œ ๋ฉ”์„œ๋“œ๋“ค์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฉ”ํƒ€ ์ •๋ณด๋“ค์„ ๊ฐ€์ง€๋Š” MethodParameter ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

/*---------------์˜ˆ์ œ ์ปจํŠธ๋กค๋Ÿฌ---------------*/
@RestController
public class MyController {

    @GetMapping("/method1")
    public User method1(@RequestParam("username") String name, @ModelAttribute User user, Model model) {
        return user;
    }

    @GetMapping("/method2")
    public String method2(HttpServletRequest request, HttpServletResponse response) {
        return "Hello, World";
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class User {
        private String username;
        private String email;
    }
}

method1์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฉ”ํƒ€ ์ •๋ณด img_4.png

method2์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฉ”ํƒ€ ์ •๋ณด img_5.png

ServletInvocableHandlerMethod

  • InvocableHandlerMethod ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•œ ์›น ์ฒ˜๋ฆฌ์šฉ ํด๋ž˜์Šค๋กœ์จ ํ•ธ๋“ค๋Ÿฌ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

  • HTTP ์š”์ฒญ ์ •๋ณด๋ฅผ ๋ถ„์„ํ•˜๊ณ  ํ•ด๋‹น ์š”์ฒญ์— ๋งคํ•‘๋˜์–ด ์žˆ๋Š” AnnotatedMethod ๊ฐ์ฒด๋ฅผ ์ฐพ์•„ ์ƒˆ๋กœ์šด ServletInvocableHandlerMethod๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ „๋‹ฌํ•œ๋‹ค.

  • AnnotatedMethod์— ์ €์žฅ๋˜์–ด ์žˆ๋Š” Method, MethodParameter ์ •๋ณด๋“ค์„ ServletInvocableHandlerMethod์— ๋ณต์‚ฌํ•œ๋‹ค.

img_6.png

RequestMappingHandlerAdapter์—์„œ HTTP ์š”์ฒญ ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ServletInvocableHandlerMethod๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

img_7.png
img_8.png
  • super() ์ƒ์„ฑ์ž๋ฅผ ๋ฐ˜๋ณตํ•ด ์ตœ์ƒ์œ„ ํด๋ž˜์Šค์ธ AnnotatedMethod ํด๋ž˜์Šค๊นŒ์ง€ ๊ฐ€์„œ ์ดˆ๊ธฐํ™” ์‹œ์ ์— ์ดˆ๊ธฐํ™”๋œ ๋ฉ”์„œ๋“œ์™€ ํŒŒ๋ผ๋ฏธํ„ฐ ์ •๋ณด๋“ค์„ ๊ทธ๋Œ€๋กœ ๋ณต์‚ฌํ•œ๋‹ค.

  • ์ดํ›„ ์š”์ฒญ ์ฒ˜๋ฆฌ์—์„œ๋Š” ์ด ๋ณต์‚ฌ๋œ ๊ฐ’๋“ค์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

img_9.png

๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ ์‹คํ–‰ ํ๋ฆ„๋„ ์š”์•ฝ

img_10.png

Last updated