Reflection
ํธ๋ค๋ฌ ๋ฉ์๋ ํธ์ถ ์๋ฆฌ ์ดํด
์ฌ์ ์ง์ : ๋ฆฌํ๋ ์
์คํ๋ง์ ํธ๋ค๋ฌ ๋ฉ์๋๋ฅผ ํธ์ถํ๊ธฐ ์ํด ๋ด๋ถ์ ์ผ๋ก ์ฌ์ฉ๋๋ ํด๋์ค๋
InvocableHandlerMethod์ ์ด๋ฅผ ํ์ฅํServletInvocableHandlerMethodํด๋์ค๊ฐ ์๋ค.๋ฉ์๋ ํธ์ถ ์ ๋ฉ์๋ ํ๋ผ๋ฏธํฐ๋ฅผ ํด์ํ๊ธฐ ์ํ
HandlerMethodArgumentResolver์ ๋ฉ์๋ ๋ฐํ ๊ฐ์ ์ฒ๋ฆฌํ๊ธฐ ์ํHandlerMethodReturnValueHandler์ ๊ฐ์ ํด๋์ค์ ์ฐ๊ณํ์ฌ ์์ฒญ์ ์ฒ๋ฆฌํ๋ค.InvocableHandlerMethod๋ ๋ฒ์ฉ์ ๋ฉ์๋ ํธ์ถ ํด๋์ค์ด๋ฉฐ,ServletInvocableHandlerMethodHTTP ์์ฒญ ๋ฐ ์๋ต ์ฒ๋ฆฌ ํด๋์ค๋ก ๊ตฌ๋ถํ ์ ์๋ค.

InvocableHandlerMethod
HTTP ํ๋กํ ์ฝ์ ๋ ๋ฆฝ์ ์ด๋ฉฐ ๋ฒ์ฉ์ ์ธ ๋ฉ์๋ ํธ์ถ ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ณ ๋งค๊ฐ๋ณ์ ์ฒ๋ฆฌ๋ฅผ ์ํด
HandlerMethodArgumentResolver๋ฅผ ์ฌ์ฉํ๋ค.๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ์ง๋ง ๋ด๋ถ์ ์ผ๋ก ๋ฐํ๊ฐ์ ์ถ๊ฐ๋ก ์ฒ๋ฆฌํ์ง๋ ์๋๋ค.

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 ์๋ต ์ํ๋ฅผ ์ค์ ํ ์ ์๋ค.

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
๋ฉ์๋๋ฅผ ํ์ํ ์ ์๊ฒ ํด์ฃผ๋ ํด๋์ค
์ด๋ ธํ ์ด์ ์ด ์ ์ฉ๋ ๋ฉ์๋๋ค์ ๋ฆฌ์คํธ๋ฅผ ๊ตฌํ๊ฑฐ๋ ๋ฉ์๋์ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ฐพ๋๋ก ๋์์ค๋ค.

MethodIntrospector
์คํ๋ง ๋ถํธ ์ด๊ธฐํ ์์ ์ ๋น ํด๋์ค๋ค์ ์ค์บํ๋ฉด์
@RequestMapping์ด ์ ์ธ๋Method๊ฐ์ฒด๋ค์ ์์ฑํ๋ค.
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์ ํ๋ผ๋ฏธํฐ ๋ฉํ ์ ๋ณด 
method2์ ํ๋ผ๋ฏธํฐ ๋ฉํ ์ ๋ณด 
ServletInvocableHandlerMethod
InvocableHandlerMethodํด๋์ค๋ฅผ ํ์ฅํ ์น ์ฒ๋ฆฌ์ฉ ํด๋์ค๋ก์จ ํธ๋ค๋ฌ์ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๊ธฐ๋ฅ์ ๊ฐ์ง๊ณ ์๋ค.HTTP ์์ฒญ ์ ๋ณด๋ฅผ ๋ถ์ํ๊ณ ํด๋น ์์ฒญ์ ๋งคํ๋์ด ์๋
AnnotatedMethod๊ฐ์ฒด๋ฅผ ์ฐพ์ ์๋ก์ดServletInvocableHandlerMethod๋ฅผ ์์ฑํ๊ณ ์ ๋ฌํ๋ค.AnnotatedMethod์ ์ ์ฅ๋์ด ์๋Method,MethodParameter์ ๋ณด๋ค์ServletInvocableHandlerMethod์ ๋ณต์ฌํ๋ค.

RequestMappingHandlerAdapter์์ HTTP ์์ฒญ ๋ง๋ค ์๋ก์ด ServletInvocableHandlerMethod๋ฅผ ์์ฑํ๋ค.


super()์์ฑ์๋ฅผ ๋ฐ๋ณตํด ์ต์์ ํด๋์ค์ธAnnotatedMethodํด๋์ค๊น์ง ๊ฐ์ ์ด๊ธฐํ ์์ ์ ์ด๊ธฐํ๋ ๋ฉ์๋์ ํ๋ผ๋ฏธํฐ ์ ๋ณด๋ค์ ๊ทธ๋๋ก ๋ณต์ฌํ๋ค.์ดํ ์์ฒญ ์ฒ๋ฆฌ์์๋ ์ด ๋ณต์ฌ๋ ๊ฐ๋ค์ ๊ทธ๋๋ก ์ฌ์ฉํ๋ค.

๋ฉ์๋ ํ๋ผ๋ฏธํฐ ์คํ ํ๋ฆ๋ ์์ฝ
Last updated
