본문 바로가기

Spring/Core

(43)
[Core] CGLIB 동적 프록시 이전 장(링크) 에서는 JDK 동적 프록시를 우리의 서비스에 적용하는 방법에 대해서 알아보았다. 이번 장에서는 인터페이스가 없는 경우에도 동적으로 프록시를 적용할 수 있는 CGLIB에 대해서 알아본다. 모든 코드는 깃허브(링크) 에 올려두었다. CGLIB (Code Generator Library) CGLIB는 이름에서 알 수 있듯이 JVM에 적재되어 있는 바이트코드를 조작하여 동적으로 클래스를 생성하는 라이브러리다. JDK 동적 프록시와는 다르게 인터페이스가 없어도 구체 클래스만 가지고 동적 프록시를 만들어낼 수 있다. CGLIB의 경우 오픈소스 라이브러리이지만 스프링 내부에 포함되어 있기 때문에 스프링을 사용한다면 따로 의존성을 주입할 필요없이 사용할 수 있다. CGLIB 적용 전 CGLIB를 통해 ..
[Core] JDK 동적 프록시 - 적용 이전 장(링크) 에서는 테스트 코드로 JDK 동적 프록시를 적용하는 방법에 대해서 알아보았다. 이번 장에서는 JDK 동적 프록시를 실제 서비스 코드에 적용하는 방법에 대해서 알아본다. 모든 코드는 깃허브(링크) 에 올려두었다. 서비스 코드 도입 InvocationHandler 인터페이스를 구현하고 있으며 LogTrace를 필드로 가지고 있는 LogTraceBasicHandler 클래스를 생성한다. 해당 클래스는 InvocationHandler를 구현하였기 때문에 JDK 동적 프록시를 생성할 때 사용된다. 또 다른 필드인 Object는 프록시가 호출하는 대상 클래스다. invoke(...) 메서드에 파라미터로 전달되는 객체와 메서드가 동적으로 변하기 때문에 이를 출력하는 코드도 정적이지 않고 동적인 것을 ..
[Core] JDK 동적 프록시 - 테스트 이전 장(링크) 에서는 JDK 동적 프록시를 이해하기 위한 선수 지식인 자바의 리플렉션에 대해서 알아보았다. 이번 장에서는 JDK 동적 프록시는 무엇이며 어떻게 사용하는지에 대해서 알아보도록 한다. 모든 코드는 깃허브(링크) 에 올려두었다. 개요 우리는 직접 인터페이스 기반 프록시와 구체 클래스 기반 프록시를 생성하면서 중복되는 코드를 가지고 있는 수없이 많은 프록시 클래스를 작성해야 하는 불편함을 느껴봤다. 동일한 역할을 하는 프록시지만 적용되는 대상이 다르기 때문에 새로운 클래스 파일을 생성해야 했다. 동일한 기능이지만 적용대상이 다르다는 이유로 새로운 클래스 파일을 생성하는 것은 상당히 비효율적이다. 이러한 문제를 해결하는 것이 동적 프록시 기술이다. 동적 프록시 기술을 사용하면 개발자가 직접 프록..
[Core] 리플렉션 이번 장에서는 동적 프록시를 이해하기 위한 선수 지식인 자바의 리플렉션에 대해서 알아보도록 한다. 모든 코드는 깃허브(링크) 에 올려두었다. 개요 우리는 이전에 인터페이스 기반 프록시 와 구체 클래스 기반 프록시 를 적용해 보면서 프록시 대상 클래스 또는 인터페이스마다 프록시 클래스를 만들어야 하는 문제를 보았다. 또한 우리가 생성한 프록시 클래스는 대부분 비슷한 모양을 하고 있었다. 당연히 우리의 선배 개발자들은 이러한 문제점을 해결하기 위해 많은 노력을 하였고 자바의 JDK 동적 프록시와 오픈소스인 CGLIB 라이브러리를 사용하면 동적으로 프록시 객체를 생성할 수 있다. 동적으로 프록시 객체를 적용하게 되면 실제 클래스를 대상으로 모든 프록시 클래스를 생성하는 것이 아니라 프록시를 적용할 코드를 만들..
[Core] 구체 클래스 기반 프록시 이전 장(링크) 에서는 인터페이스 기반의 프록시에 대해서 알아보았다. 이번 장에서는 인터페이스가 없는 구체 클래스에 프록시를 적용시키는 방법에 대해서 알아본다. 모든 코드는 깃허브(링크) 에 올려두었다. 프록시 적용 전 & 적용 후 비교 이전 장에서는 인터페이스를 기반으로 프록시를 도입하였다. 다시 프록시가 도입되기 전의 클래스와 객체의 관계를 확인해본다. 자바의 다형성은 인터페이스 뿐만 아니라 상속을 통해서도 가능하다. 즉, 인터페이스가 없더라도 클래스를 기반으로 상속을 통해서 프록시를 도입할 수 있다는 의미가 된다. 구체 클래스를 상속받아서 생성된 프록시를 적용하면 아래와 같은 클래스 의존 관계가 만들어진다. 클라이언트는 구체 클래스에 의존하고 프록시 클래스는 구체 클래스를 상속받고 있다. 런타임 시..
[Core] 인터페이스 기반 프록시 이번 장에서는 인터페이스 기반의 프록시를 생성하는 방법에 대해서 알아본다. 모든 코드는 깃허브(링크) 에 올려두었다. 프록시 적용 전 & 적용 후 비교 프록시를 적용하기 전의 클래스 의존 관계를 살펴보면 아래와 같다. 클라이언트는 컨트롤러 인터페이스인 OrderControllerV1을 의존하고 있다. 컨트롤러 구현체인 OrderControllerV1Imple은 서비스 인터페이스인 OrderServiceV1을 의존하고 있다. 런타임 시점에 객체들 간 의존 관계는 아래와 같다. 컨트롤러와 서비스에 인터페이스 기반의 프록시를 적용하면 아래와 같은 클래스 의존 관계가 형성된다. 컨트롤러 인터페이스를 구현하는 클래스가 기존 구현 클래스 한 개에서 프록시 구현체가 추가되었다. 서비스 인터페이스 또한 동일하다. 클라..
[Core] 데코레이터 패턴 이번 장에서는 이전 장(링크) 에 알아본 프록시 패턴에 이어 데코레이터 패턴 에 대해서 알아본다. 모든 코드는 깃허브(링크) 에 올려두었다. 데코레이터 패턴 데코레이터 패턴 의 경우 프록시 패턴과 형태가 동일하다. 하지만 둘은 사용하는 의도(Intent)가 다르다는 차이가 있다. 데코레이터 패턴은 런타임 환경에서 객체에 추가 책임을 동적으로 추가하고 싶은 경우에 사용하게 된다. 데코레이터 패턴을 적용하기 전의 클래스 의존 관계를 보면 아래와 같다. Client는 인터페이스인 Component를 의존하고 있고 RealComponent는 Component를 구현하고 있다. 런타임 환경에서는 Client 객체가 구현체인 RealComponent의 객체를 의존하게 된다. 데코레이터 패턴 적용 전 데코레이터 패턴..
[Core] 프록시 패턴 이번 장에서는 스프링의 프록시와 프록시 패턴에 대해서 알아본다. 모든 코드는 깃허브(링크) 에 올려두었다. 프록시 우리는 지금까지 주로직과 부로직을 분리하기 위해 템플릿 메서드 패턴, 전략 패턴, 템플릿 콜백 패턴을 사용하였다. 이런 디자인 패턴들을 적용하여도 부로직을 적용하기 위해서 주로직이 변경되어야 한다는 문제점은 해결하지 못하였다. 결국 주로직이 있는 원본 코드를 전혀 수정하지 않고 부로직을 적용시키기 위해서는 프록시(Proxy) 라는 기술을 적용해야 한다. 클라이언트(Client)와 서버(Server)는 일반적으로 PC와 서버로 구분되지만 실제로는 더 넓게 사용되고 있다. 우리가 잘알고 있는 게임을 예로 들면 게임을 작동시키는 PC가 클라이언트가 되고 게임을 중개하는 서버가 서버가 된다. 개발자..