본문 바로가기
Spring/디자인패턴

Proxy pattern(프록시 패턴)

by 미눅스[멘토] 2023. 7. 21.
728x90

 

 

Proxy는 대리인 이라는 뜻으로써, 뭔가를 대신해서 처리하는 것

Proxy Class를 통해서 대신 전달 하는 형태로 설계되며, 실제 Client는  Proxy로 부터 결과를 받는다.

Cache의 기능으로도 활용이 가능 하다.

SOLID중에서 개방폐쇄 원칙 (OCP)과 의존 역전 원칙(DIP)를 따른다.

 

 

 

구조 패턴 카테고리
클라이언트는 실제객체 대신 Proxy 객체를 통해 작업요청

proxy는 실제격체와 클라이언트 사이에 존재

 

적용사례

Access Control / Validation
Caching / Logging

Debit / check Card (banking)

 

 

 

프록시 패턴을 이용한 캐싱기능

-브라우저, 인터넷 통신에서 이미 받아둔 결과가 있다면 결과를 그 결과를 그대로 내려주거나

서버에서도 특정한 데이터들, 자주변경되지 않는 데이터들 같은 경우에는 메모리 같은 것에다

캐싱을 해놨다가 같은 결과를 요청해 왔을때 내려주는 형태로 사용함.

 

 

 

IBrowser (인터페이스) 구현

package Muzi.proxy;

public interface IBrowser {
	Html show();
}

 

Browser (클래스) = IBrowser상속

package Muzi.proxy;

public class Browser implements IBrowser {

	private String url;
	
	public Browser(String url) {
		this.url = url;
	}
	
	
	@Override
	public Html show() {
		System.out.println("browser loading html from : " + url);
		return new Html(url);
	}
}

Html(클래스)

package Muzi.proxy;

public class Html {
	private String url;
	
	public Html(String url) {
		this.url = url;
	}
}

 

Main(클래스) 

package Muzi;

import java.util.concurrent.atomic.AtomicLong;

import Muzi.aop.AopBrowser;
import Muzi.proxy.Browser;
import Muzi.proxy.BrowserProxy;
import Muzi.proxy.IBrowser;

public class Main {
	public static void main(String[] args) {
		//여러번 페이지를 본다
		//매번 로딩이 일어남
		Browser browser = new Browser("www.naver.com");
		browser.show();
		browser.show();
		browser.show();
		browser.show();
		browser.show();
		
		/*
		IBrowser browser = new BrowserProxy("www.naver.com");
		browser.show();
		browser.show();
		browser.show();
		browser.show();
		browser.show();
		
		AtomicLong start = new AtomicLong();
		AtomicLong end = new AtomicLong();
		
		IBrowser aopBrowser = new AopBrowser("www.naver.com",
			()->{
				System.out.println("before");
				start.set(System.currentTimeMillis());
			},
			()->{
				long now = System.currentTimeMillis();
				end.set(now - start.get());
			}
		);
		aopBrowser.show();
		System.out.println("loding time : " + end.get());
		
		aopBrowser.show();
		System.out.println("loding time : " + end.get());
		 */
		
	}
}

 

콘솔에 보면 매번 loding이 일어나는 것을 볼 수 있다.

하지만 프록시 패턴을 쓴다면?

 

 

 

 

BrowserProxy(클래스) = IBrowser(상속)

package Muzi.proxy;

public class BrowserProxy implements IBrowser{

	//캐싱을 하기 위해서 두 가지를 가질 수 잇다.
	private String url;
	//html 캐싱
	private Html html;
	
	//기본생성자로 url받음
	public BrowserProxy(String url) {
		this.url = url;
	}
	
	@Override
	public Html show() {
		
		if(html == null) {
			this.html = new Html(url);
			System.out.println("BrowserProxy lodding html from : " + url);
		}
		
		System.out.println("BrowserProxy use cache html from : " + url);
		return html;
	}
}

 

 

Main(클래스)

package Muzi;

import java.util.concurrent.atomic.AtomicLong;

import Muzi.aop.AopBrowser;
import Muzi.proxy.Browser;
import Muzi.proxy.BrowserProxy;
import Muzi.proxy.IBrowser;

public class Main {
	public static void main(String[] args) {
		//여러번 페이지를 본다
		//매번 로딩이 일어남
		/*
		 
		Browser browser = new Browser("www.naver.com");
		browser.show();
		browser.show();
		browser.show();
		browser.show();
		browser.show();
		 */
		
		IBrowser browser = new BrowserProxy("www.naver.com");
		browser.show();
		browser.show();
		browser.show();
		browser.show();
		browser.show();
		
		/*
		AtomicLong start = new AtomicLong();
		AtomicLong end = new AtomicLong();
		
		IBrowser aopBrowser = new AopBrowser("www.naver.com",
			()->{
				System.out.println("before");
				start.set(System.currentTimeMillis());
			},
			()->{
				long now = System.currentTimeMillis();
				end.set(now - start.get());
			}
		);
		aopBrowser.show();
		System.out.println("loding time : " + end.get());
		
		aopBrowser.show();
		System.out.println("loding time : " + end.get());
		 */
		
	}
}

 

 

 

Main(클래스)

 

 

 

콘솔에 보면 한번만 로딩이 되고

나머지 캐싱에 저장된 html로 불러오는것 을 볼 수 있다!!!

그렇다면 이번에는

프록시 패턴으로 

AOP를 구현해보자

 

 

 

AOP는 Aspect Oriented Programming의 약자로 관점 지향 프로그래밍이라고 불린다. 관점 지향은 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 모듈화 하겠다는 것이다.

 

*모듈화 : 어떤 공통된 로직이나 기능을 하나의 단위로 묶는 것 

 

예를 들어 핵심적인 관점은 비즈니스 로직이 될 수 있고, 부가적인 관점은 핵심 로직을 실행하기 위해 행해지는 데이터베이스 연결, 로깅, 파일 입출력 등이 될 수 있다. 

 

AOP는 관점지향

 

 

 

AopBrowser(클래스)

package Muzi.aop;

import Muzi.proxy.Html;
import Muzi.proxy.IBrowser;

public class AopBrowser implements IBrowser{
	
	private String url;
	private Html html;
	private Runnable before;
	private Runnable after;
	
	public AopBrowser(String url, Runnable before, Runnable after) {
		this.url = url;
		this.before = before;
		this.after = after;		
	}
	
	
	@Override
	public Html show() {
		before.run();
		
		
		if(html == null) {
			this.html = new Html(url);
			System.out.println("AopBrowser html loading from : " + url);
			
			try {
				Thread.sleep(1500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		after.run();
		System.out.println("AopBrowser html cache : " + url);
		
		return html;
	}
}

 

Main(클래스)

package Muzi;

import java.util.concurrent.atomic.AtomicLong;

import Muzi.aop.AopBrowser;
import Muzi.proxy.Browser;
import Muzi.proxy.BrowserProxy;
import Muzi.proxy.IBrowser;

public class Main {
	public static void main(String[] args) {
		//여러번 페이지를 본다
		//매번 로딩이 일어남
		/*
		 
		Browser browser = new Browser("www.naver.com");
		browser.show();
		browser.show();
		browser.show();
		browser.show();
		browser.show();
		
		IBrowser browser = new BrowserProxy("www.naver.com");
		browser.show();
		browser.show();
		browser.show();
		browser.show();
		browser.show();
		 */
		
		AtomicLong start = new AtomicLong();
		AtomicLong end = new AtomicLong();
		
		IBrowser aopBrowser = new AopBrowser("www.naver.com",
			()->{
				System.out.println("before");
				start.set(System.currentTimeMillis());
			},
			()->{
				long now = System.currentTimeMillis();
				end.set(now - start.get());
			}
		);
		aopBrowser.show();
		System.out.println("loding time : " + end.get());
		
		aopBrowser.show();
		System.out.println("loding time : " + end.get());
		
	}
}

 

콘솔에 

before 에 보면

loading 된것을 볼 수 있고

cache가 사용된것을 볼 수 있고

loding time이 1.5초가 걸린것을 볼 수 있다.

 

하지만 두번째 불러온

 

before는

cache를 이용해 로딩이 시간이 없고

ache를 이용했기 떄문에

loding tome : 0초가 걸린것을 볼 수 있다