AOP
AOP
Aspect Oriented Programming (관점 지향 프로그래밍)
transaction, logging, security와 관련된 코드들을 분리하여 관리.
proxy, target, real subject
Proxy(프록시) : 자신이 클라이언트가 사용하려고 하는 실제 대상인 것처럼 위장해서 클라이언트의 요청을 받아주는 것을 대리자, 대리인과 같은 역할을 한다고 해서 프록시라고 부른다.
Target(타깃), Real subject(실체) : 프록시를 통해 최종적으로 요청을 위임받아 처리하는 실제 오브젝트.
프록시는 타깃과 같은 인터페이스를 구현한다.
프록시가 타깃을 제어할 수 있는 위치에 있다.
데코레이터 패턴
타깃에 부가적인 기능을 런타임에 다양하게 부여해주기 위해 프록시를 사용하는 패턴.
데코레이터 패턴에서는 같은 인터페이스를 구현한 타겟과 여러개의 프록시를 사용할 수 있다. 프록시가 여러개인 만큼 순서를 정해서 단계적으로 위임하는 구조로 만든다.
데코레이터 패턴의 대표적인 예 : InputStream, OutputStream 구현 클래스
InputStream is = new BufferedInputStream(new FileInputStream("a.txt"));
InputStream이라는 인터페이스를 구현한 타깃인 FileInputStream에 버퍼 읽기 기능을 제공해주는 BufferedInputStream이라는 데코레이터를 적용한 예이다.
프록시 패턴
프록시를 사용하는 방법 중에서 타깃에 대한 접근 방법을 제어하려는 목적을 가진 경우.
타깃의 기능 자체에는 관여하지 않으면서 접근하는 방법을 제어해주는 프록시를 이용.
- 타깃 오브젝트를 생성하기가 복잡하거나 당장 필요하지 않지만 타깃 오브젝트에 대한 레퍼런스가 미리 필요할 때 프록시 패턴을 적용하면 된다. 클라이언트에게 타깃에 대한 레퍼런스를 넘겨야 하는데, 실제 타깃 오브젝트를 만드는 대신 프록시를 넘겨준다. 그리고 프록시의 메소드를 통해 타깃을 사용하려고 시도하면, 그 때 프록시가 타깃 오브젝트를 생성하고 요청을 위임한다.
- 다른 서버에 존재하는 오브젝트를 사용해야 할 때, 원격 오브젝트에 대한 프록시를 만들어두고, 클라이언트는 로컬에 존재하는 오브젝트를 쓰는 것 처럼 프록시를 사용하게 할 수 있다. 프록시는 클라이언트의 요청을 받으면 네트워크를 통해 원격의 오브젝트를 실행하고 결과를 받아서 클라이언트에게 돌려준다.
- 특별한 상황에서 타깃에 대한 접근권한을 제어하기 위해 프록시 패턴을 사용할 수 있다. 수정가능한 오브젝트를, 특정 레이어로 넘어가면 읽기전용으로만 동작하게 강제해야 하는 경우, 오브젝트의 프록시를 만들어서 사용할 수 있다. 프록시의 특정 메소드를 사용하려고 하면 접근이 불가능하다고 예외를 발생시키면 된다.
다이나믹 프록시
다이나믹 프록시는 리플렉션 기능을 이용해서 프록시를 만들어준다.
다이나믹 프록시는 프록시 팩토리에 의해 런타임 시 다이나믹하게 만들어지는 오브젝트다. 다이나믹 프록시 오브젝트는 타깃의 인터페이스와 같은 타입으로 만들어진다.
클라이언트는 다이나믹 프록시 오브젝트를 타깃 인터페이스를 통해 사용할 수 있다.
프록시 팩토리에게 인터페이스 정보만 제공해주면 해당 인터페이스를 구현한 클래스의 오브젝트를 자동으로 만들어준다.
프록시로서 필요한 부가기능 제공을 위해 프록시 오브젝트와 독립적으로 InvocationHandler
인터페이스를 구현한다.
public Object invoke(Object proxy, Method method, Object[] args)
invoke()
메소드는 리플렉션의 Method 인터페이스를 파라미터로 받는다.
메소드를 호출할 때 전달되는 parameter도 args로 받는다.
다이나믹 프록시 오브젝트는 클라이언트의 모든 요청을 리플렉션 정보로 변환해서 InvocationHandler
구현 오브젝트의 invoke()
메소드로 넘기는 것이다.
다이나믹 프록시로부터 요청을 전달받으려면 InvocationHandler를 구현해야 한다. 메소드는 invoke() 하나 뿐이다. 다이나믹 프록시가 클라이언트로부터 받는 모든 요청은 invoke() 메소드로 전달된다. 다이나믹 프록시를 통해 요청이 전달되면 리플렉션 API를 이용해 타깃 오브젝트의 메소드를 호출한다.
다이나믹 프록시의 생성은 Proxy 클래스의 newProxyInstance() 스태틱 팩토리 메소드를 이용하면 된다.
팩토리 빈
스프링을 대신해서 오브젝트의 생성로직을 담당하도록 만들어진 특별한 빈.
FactoryBean
이라는 인터페이스를 구현한 클래스를 스프링의 빈으로 등록해서 팩토리빈을 사용할 수 있다.
Advice
advice : MethodInterceptor 처럼 target object에 적용하는 부가 기능을 담은 object
포인트컷: 부가기능 적용 대상 메소드 선정 방법
스프링은 부가기능을 제공하는 오브젝트를 어드바이스라고 부르고, 메소드 선정 알고리즘을 담은 오브젝트를 포인트컷이라고 부른다.
프록시는 클라이언트로부터 요청을 받으면 먼저 포인트컷에게 부가기능을 부여할 메소드인지 확인해달라고 요청한다. 포인트컷은 Pointcut interface를 구현해서 만들면 된다. 프록시는 포인트컷으로부터 부가기능을 적용할 대상 메소드인지 확인받으면, MethodInterceptor 타입의 어드바이스를 호출한다.
확장된 포인트컷
포인트컷은 아래 두가지 역할을 수행한다.
- 타깃 오브젝트의 메소드 중에서 어떤 메소드에 부가 기능을 적용할지를 선정해주는 역할
- 등록된 빈 중에서 어떤 빈에 프록시를 적용할지를 선택하는 역할
포인트컷은 클래스 필터와 메소드 매처 두 가지를 돌려주는 메소드를 갖고 있다.
메소드만 선별하는 것 뿐 아니라, 프록시를 적용할 클래스인지 판단하고 나서, 적용대상 클래스인 경우에는 어드바이스를 적용할 메소드인지 확인하는 식으로 활용이 가능하다.
포인트컷 표현식
pointcut expression : 일종의 표현식 언어를 사용해서 포인트컷을 작성할 수 있도록 하는 방법.
AspectJExpressionPointcut
클래스를 사용하면 포인트컷 표현식을 지원하는 포인트컷을 적용할 수 있다. 클래스와 메소드의 선정 알고리즘을 포인트컷 표현식을 이용해 한 번에 지정할 수 있게 해준다.
AOP: 애스펙트 지향 프로그래밍
Aspect : 그 자체로 애플리케이션의 핵심기능을 담고 있지는 않지만, 애플리케이션을 구성하는 중요한 한 가지 요소이고, 핵심기능에 부가되어 의미를 갖는 특별한 모듈을 가리킨다. 애스펙트는 부가될 기능을 정의한 코드인 어드바이스와, 어드바이스를 어디에 적용할지를 결정하는 포인트컷을 함께 갖고 있다.
Aspect Oriented Programming : 애플리케이션의 핵심적인 기능에서 부가적인 기능을 분리해서 애스펙트라는 독특한 모듈로 만들어서 설계하고 개발하는 방법.
기타 용어
join point : 어드바이스가 적용될 수 있는 위치를 말한다 . 스프링의 프록시 AOP에서 조인 포인트는 메소드의 실행 단계뿐이다. 타깃 오브젝트가 구현한 인터페이스의 모든 메소드는 조인 포인트가 된다.
Advisor : 어드바이저는 포인트컷과 어드바이스를 하나씩 갖고 있는 오브젝트다.