2024-09-24-TIL
Today I Learned
Spring MVC Request Life Cycle
Spring MVC가 요청 하나를 처리하는 순서를 다시 확인했다. 요청은 먼저 모든 요청에 적용되는 Filter를 지나고, DispatcherServlet이 요청을 분석해 알맞은 컨트롤러로 보낸다. 그 사이에 Handler mapping이 요청을 컨트롤러 메서드에 연결하고, Handler interceptor가 핸들러 앞뒤에서 공통 검사를 수행한다. 처리 중 예외는 HandlerExceptionResolver가, 컨트롤러가 돌려준 논리적인 뷰 이름은 ViewResolver가 맡는다.
Filter와 Interceptor는 둘 다 요청 전후 처리를 하지만 실행 시점과 등록 위치가 다르다. Filter는 웹 애플리케이션(서블릿 컨테이너)에 등록되고, Interceptor는 Spring 컨텍스트에 등록되어 DispatcherServlet 안에서 실행된다. NHN Cloud Meetup 글은 이 차이가 가장 크게 드러나는 곳을 예외 처리로 본다. Interceptor에서 난 예외는 @ControllerAdvice와 @ExceptionHandler로 처리할 수 있지만, Filter에서 난 예외는 Spring 바깥의 웹 애플리케이션이 처리해야 한다.
Java 23
Oracle은 2024년 9월 17일 Java 23을 발표했다. 발표문에 실린 변경 중 눈에 띄는 것은 다음과 같다.
- JEP 455: 패턴 매칭,
instanceof,switch에서 primitive 타입 패턴 허용 (Preview) - JEP 476: 모듈이 export하는 패키지를 한 번에 가져오는 Module Import Declarations (Preview)
- JEP 467: Javadoc 주석을 HTML 대신 Markdown으로 작성
- JEP 474: ZGC의 기본 모드를 generational 모드로 전환
- JEP 473: Stream Gatherers (Second Preview), JEP 480: Structured Concurrency (Third Preview)
Java Proxy
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.
To create a proxy for some interface Foo:
1
2
3
4
InvocationHandler handler = new MyInvocationHandler(...);
Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
newInstance(handler);
or more simply:
1
2
3
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class<?>[] { Foo.class },
handler);
A dynamic proxy class (simply referred to as a proxy class below) is a class that implements a list of interfaces specified at runtime when the class is created, with behavior as described below. A proxy interface is such an interface that is implemented by a proxy class. A proxy instance is an instance of a proxy class. Each proxy instance has an associated invocation handler object, which implements the interface InvocationHandler. A method invocation on a proxy instance through one of its proxy interfaces will be dispatched to the invoke method of the instance’s invocation handler, passing the proxy instance, a
java.lang.reflect.Methodobject identifying the method that was invoked, and an array of type Object containing the arguments. The invocation handler processes the encoded method invocation as appropriate and the result that it returns will be returned as the result of the method invocation on the proxy instance.
위 인용은 java.lang.reflect.Proxy Javadoc이다. 정리하면 JDK 동적 프록시는 런타임에 지정한 인터페이스 목록을 구현하는 클래스를 만들고, 프록시의 모든 메서드 호출을 InvocationHandler.invoke() 한 곳으로 모은다. 그래서 인터페이스가 있어야만 프록시를 만들 수 있다.
Java Reflection
리플렉션은 실행 중인 Java 프로그램이 자기 자신을 들여다보고(introspect) 내부 속성을 조작할 수 있게 하는 기능이다. 클래스의 메서드, 필드, 생성자 정보를 런타임에 얻고 호출할 수 있으며, 위의 동적 프록시도 호출된 메서드를 java.lang.reflect.Method 객체로 넘겨받는다.
JDK Dynamic Proxy와 CGLIB
Spring AOP는 프록시를 만들 때 타깃이 인터페이스를 구현하는지 먼저 본다. 하나 이상의 인터페이스를 구현한 클래스라면 JDK Dynamic Proxy로, 그렇지 않으면 CGLIB으로 프록시를 생성한다. JDK Dynamic Proxy는 인터페이스를 기준으로 프록시를 만들기 때문에 주입받는 쪽도 인터페이스 타입이어야 한다. CGLIB은 클래스의 바이트코드를 조작해 타깃 클래스를 상속한 프록시를 만든다. 참고한 글에 따르면 Spring Boot는 CGLIB 방식을 기본 프록시 생성 방법으로 쓴다.
cglib 저장소 README에는 cglib이 더 이상 유지보수되지 않고 JDK 17 이후에서는 잘 동작하지 않을 수 있으니 ByteBuddy 같은 대안으로 옮기라는 안내가 붙어 있다.
참고한 자료외부 출처 18
외부 출처
- Spring MVC Request Life CycleJust For Change
- (Spring)Filter와 Interceptor의 차이
- Servlet Container and Spring Framework
- Servlet things every Java Developer must know — Servlet, Container, Filter, and Listener
- Oracle Releases Java 23
- Proxy란 (with Java)
- Proxy (Java Platform SE 8)
- Dynamic Proxy Classes
- Dynamic Proxies in Java
- Using Java Reflection
- [Java] Reflection은 무엇이고 언제/어떻게 사용하는 것이 좋을까?
- Guide to Java Reflection
- Java Reflection 개념 및 사용법현재 열리지 않음
- 자바 리플렉션 (Reflection) 기초
- What is reflection and why is it useful?
- JDK Dynamic Proxy와 CGLIB의 차이점은 무엇일까?
- cglib/cglib
- [Spring] CGLIB
댓글
아직 댓글이 없습니다