[Design Pattern] 프록시 패턴

이재훈·2023년 8월 27일
0

디자인패턴

목록 보기
6/6

자주 사용되는 디자인 패턴

프록시 패턴

월래 객체를 대신하여 요청을 받아 원래 객체를 호출하기 전이나 후에 특정 로직을 실행하는 패턴을 말합니다. 여기서의 중요 포인트는 원래 객체가 호출되기는 한다는 것과, 전이나 후에 특정 로직을 넣을 수 있다는 점입니다.

프록시 패턴 구현 방법

public interface SomeInterface {
	void someMethod();
}
public class Service implements SomeInterface {
	@Override
    public void someMethod() {
    	System.out.print("Serivce의 SomeMethod");
    }
}
public class Proxy implement SomeInterface {
	private Service service;
    
    public Proxy() {
    	this.service = new Service();
    }

	@Override
    public void someMethod() {
    	System.out.print("someMethod 실행 전");
        
        service.someMethod();
        
        System.out.print("someMethod 실행 후");
    }
}

프록시 패턴을 구현하기 위해서는 하나의 인터페이스와 해당 인터페이스를 구현한 두 개의 클래스가 필요합니다.하나는 실제 로직을 가지고 있는 Service 클래스와 Proxy 클래스를 만듭니다. 같은 someMethod를 오버라이딩 했지만 Proxy 클래스의 someMethod 에는 service의 someMethod를 호출하고 있고 그 앞 뒤에 로직을 넣을 수 있습니다.

실제로 사용하는 코드를 아래에서 확인할 수 있습니다.

public class ProxyPatternMain {
	public static void main(String[] args) {
    	Proxy proxy = new Proxy();
        Client client = new Client(proxy);
        
        client.someClientMethod();
    }
}
public class Client {
	private final SomeInterface someInterface;
    
    public Client(SomeInterface someInterface) {
    	this.someInterface = someInterface;
    }
    
    public void someClientMethod() {
    	someInterface.someMethod();
    }
}

ProxyPatternMain 클래스에서는 Proxy 객체를 생성하고 Client에 생성자의 매개변수로 넣어줍니다. Client 클래스는 someInterface 안에 있는 someMethod 메서드를 호출시켜줍니다. 실제로 우리가 프록시 패턴을 사용할 때는 스프링 프레임 워크가 프록시 객체를 생성해주고 실행시켜주는 역할을 합니다.

AOP (Aspect Oriented Programming), 관점 지향 프로그래밍

AOP는 스프링 프레임 워크가 제공하는 핵심 기능 중 하나입니다. 관점 지향 프로그래밍은 어떤 로직을 핵심적인 로직과 부가적인 로직으로 나누고, 반복되는 부가적인 로직을 분리하여 감추는 것 입니다. 어떤 로직에서 부가적인 로직이 없어지고 핵심적인 로직만 남기 때문에 핵심적인 로직의 가독성이 올라갑니다.

어떤 것이 핵심적인 로직이고 어떤 것이 부가적인 로직일까요?

public ... createPost(...) {
	postRepository.save(...); // 핵심적인 로직
	
    alarmPublisher.sendAlarm(...); // 부가적인 로직
}

public ... createComment(...) {
	commentRepository.save(...); // 핵심적인 로직
	
    alarmPublisher.sendAlarm(...); // 부가적인 로직
}

createPost와 createComment 메서드의 핵심적인 로직은 게시글과, 댓글을 저장하는 것입니다. 부가적인 로직은 해당 게시글, 댓글이 등록되었다는 것을 알림 메시지 보내주는 기능입니다.
현재 부가적인 로직은 또 코드가 중복되고 있습니다.

현재 이 코드에서 부가적인 로직이 알림 메시지를 보내는 코드일 뿐이지 상황에 따라 알림 메시지를 보내는 것이 핵심적인 로직일 수 있습니다. 이럴 때는 중복 코드가 발생하더라도 AOP를 적용하는 것을 보수적으로 생각해 볼 수 있습니다.

스프링에서 프록시를 사용하는 방법은 여러가지가 있습니다. 위의 그림에서는 @SendAlarm 애너테이션이 붙어있는 메서드 실행 후에 알림 메시지를 보내는 기능을 추가하는 코드를 작성하면 AOP가 적용되어 해당 메서드 실행 후에 자동으로 알림 메시지를 보내게 합니다.

@Around("@annotation(SendAlarm)")
public void sendAlarm(ProceedingJoinPoint pjp) {
	Object returnValue = pjp.proceed();
    
    alarmPublisher.sendAlarm(...);
}

위의 코드는 간략적으로 이렇게 사용한다라고 보여주는 예시입니다.

Client에서 진짜 객체를 호출하지 않고 공통의 인터페이스를 가진 프록시 객체를 호출하고 프록시 객체가 그 안에서 진짜 객체를 호출합니다. 이 구성에서 프록시 패턴을 직접 구현하려면 프록시 클래스를 직접 만들어야 합니다. 별도의 인터페이스도 직접 구현해야 합니다.

하지만 스프링 프레임워크를 사용하면 직접 인터페이스를 만들지 않아도, 프록시 객체를 만들지 않아도 됩니다. 스프링 프레임워크가 어떤 곳에 AOP 설정이 되어있는지 확인을 하고 프록시 객체를 등록해 둡니다. 여기서 알아둬야 할 것은 스프링 AOP의 근간은 프록시 패턴이다 라는 것을 알아두어야 합니다.

Self Invocation

진짜 객체 내부에서 this를 통해 내부의 메서드를 호출하려고 할 때 생기는 문제입니다. 이렇게 되면 AOP가 걸려있는 메서드인데 AOP가 적용되지 않게 됩니다. 문제를 해결하는 방법은 여러가지가 있습니다. 이 게시글에서는 해결 방안보다 this가 있을 때 Self Invocation이 발생할 수 있다는 것을 알려드립니다.

프록시 패턴이 적용되면서 생긴 장점 & 보호하고자 하는 것

프록시 패턴이 적용되면서 코드의 가독성이 올라가고 부가적인 로직과 핵심적인 로직을 분리하여 유지보수 측면에서도 큰 이득을 가져오게 됩니다. 프록시 패턴이 보호하려는 것은 클라이언트 코드가 아닌 서버 코드입니다. 부가적인 코드의 변경이 필요할 때에도 핵심코드의 변경 없이 변경이 가능하게 되는 것 입니다.

결론

최근 회사에서 AOP를 사용하여 핵심 로직과 부가적인 코드를 분리하여 코드를 굉장히 많이 줄인 경험이 있습니다. 그렇기에 이번 회차는 굉장히 크게 더 와닿았던 것 같습니다.


해당 게시글은 프로그래머스 스쿨 강의
"실무 자바 개발을 위한 OOP와 핵심 디자인 패턴(푸)"
를 정리한 내용입니다. 쉽게 잘 설명해주시니 여러분도 강의를 듣는 것을 추천드립니다.

profile
부족함을 인정하고 노력하자

0개의 댓글