일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 자바서블릿
- jQueryUI
- 페이징
- calendar
- springflow
- paging
- fetchjoin
- JPQL
- 페치조인
- Hibernate
- 벌크연산
- joinfetch
- 프로젝트생성
- 스프링데이터흐름
- 대량쿼리
- jscalendar
- values()
- 제너릭
- javaservlet
- 제네릭
- JQuery
- JPA
- LIST
- 엔티티직접사용
- jQuery값전달
- namedQuery
- javascriptcalendar
- fullcalendar
- jQuery값전송
- Generic
- Today
- Total
가자공부하러!
Proxy 본문
참고 : https://refactoring.guru/design-patterns/proxy
1. Proxy?
1.1. 프록시란?
- 다른 객체를 대신할 수 있게 해주는 구조적 디자인 패턴
- 원본객체로의 접근을 제어 : 원본객체로의 요청전 또는 요청 후에 어떤 작업을 할 수 있게 해준다.
- 프록시는 서비스 객체인 것 처럼 위장해서 지연로딩과 결과캐싱 등을 다룰 수 있다.
1.2. 프록시의 구조
- ServiceInterface : 프록시는 이 인터페이스를 따라서 자신을 서비스 객체로 위장
- Service : 유용한 비즈니스 로직을 제공하는 클래스
- Proxy
> Proxy 클래스에는 서비스 객체(Service)를 가리키는 참조 필드가 존재
> 프록시가 처리를 마치면(지연 초기화, 로깅, 액세스 제어, 캐싱 등) 요청을 서비스 객체로 전달
> 일반적으로 프록시는 서비스 개체의 전체 수명주기를 관리
- Client
> 서비스 객체(Service)가 필요한 모든 코드에 프록시를 전달할 수 있음
- 조건 : 클라이언트는 동일한 인터페이스를 통해 서비스와 프록시 모두에서 작동해야 한다.
2. 프록시 응용
2.1. 지연 초기화(Lazy Initialization)
- 무거운 서비스 객체가 있는 경우, 앱이 실행될 때 객체를 생성하는 대신 객체가 실제 필요할 때 초기화를 수행
2.2. 액세스 제어(Protection Proxy)
- 특정 클라이언트만 서비스 객체를 사용할 수 있게 제어
- 프록시는 클라이언트의 자격증명이 미리 정해둔 기준과 일치하는 경우에만 요청을 서비스 객체에 전달
2.3. 원격 서비스(Remote Proxy)
- 서비스 객체가 원격 서버에 위치하는 경우
- 프록시는 네트워크를 통해 클라이언트 요청을 전달하여 네트워크 작업에 대한 모든 세부 정보를 처리
2.4. 로깅 요청(Logging Proxy)
- 서비스 객체로의 요청에 대한 이력을 남기고 싶은 경우
- 프록시는 각각의 요청을 서비스 객체에 전달하기 전에 로그를 남긴다.
2.5. 캐싱 요청 결과(Caching Proxy)
- 규모가 큰 클라이언트의 요청 결과를 캐싱하고 캐시의 수명주기를 관리해야 하는 경우
- 항상 동일한 결과를 갖는 반복 요청에 대해 캐싱을 구현할 수 있다.
- 프록시는 리퀘스트의 매개변수를 캐시의 키로 사용할 수 있다.
2.6. Smart Reference
- 어떤 사용자도 사용하지 않고 있는 무거운 객체를 없애고 싶을 때
- 프록시는 클라이언트 목록이 비어있다면, 서비스 오브젝트를 닫고 시스템 자원을 회수할 수 있음
> 프록시는 서비스 객체나 결과에 대한 참조를 얻은 사용자를 추적할 수 있음
> 프록시는 클라이언트들이 활성상태인지 조사할 수 있음
- 클라이언트가 서비스 객체를 수정했는지에 대한 여부를 추적할 수 있음
> 변경되지 않은 서비스 객체의 경우 다른 클라이언트에서 재사용 가능
3. 구현 방법
3.1. 서비스 인터페이스 준비
- 기존 서비스 인터페이스가없는 경우 프록시와 서비스 개체를 상호 교환 할 수있는 인터페이스를 생성
- 서비스 클래스에서 인터페이스를 추출하는 것이 불가능한 경우
> 프록시를 서비스 클래스의 하위 클래스로 설정(상속)
3.2. 프록시 클래스를 작성
- 서비스에 대한 참조를 저장하기위한 필드 필요
- 일반적으로 프록시는 서버의 전체 수명주기를 만들고 관리
> 클라이언트가 생성자를 통해 서비스를 프록시로 전달하는 경우도 드물게 있음
3.3. 목적에 따른 프록시 방법 구현
- 대부분의 경우, 작업을 수행 한 후 프록시는 작업을 서비스 객체에 위임해야 함
3.4. 생성기법 안내에 대한 고려
- 클라이언트가 프록시의 서비스를 받는지 실제 서비스를 받는지 여부
- 프록시 클래스의 간단한 정적 메소드이거나 완전한 팩토리 메소드일 수 있음
3.5. 서비스 객체에 대한 지연 초기화 구현
3.6. 예제
- 원본 : https://refactoring.guru/design-patterns/proxy/java/example
- 직접 수행해본 코드 : https://github.com/HyeongJunMin/SpringBootOnmacOS/tree/master/proxydemo
package com.exam.proxydemo.service;
import com.exam.proxydemo.domain.Video;
import java.util.HashMap;
/**서비스 인터페이스 */
public interface ThirdPartyYoutubeLib {
HashMap<String, Video> popularVideos();
Video getVideo(String videoId);
}
package com.exam.proxydemo.service;
import com.exam.proxydemo.domain.Video;
import java.util.HashMap;
/**서비스 클래스(원본 객체) */
public class ThirdPartyYoutubeClass implements ThirdPartyYoutubeLib {
@Override
public HashMap<String, Video> popularVideos() {
connectToServer("http://www.youtube.com");
return getRandomVideos();
}
@Override
public Video getVideo(String videoId) {
connectToServer("http://www.youtube.com/" + videoId);
return getSomeVideo(videoId);
}
// -----------------------------------------------------------------------
// Fake methods to simulate network activity. They as slow as a real life.
private int random(int min, int max) {
return min + (int) (Math.random() * ((max - min) + 1));
}
private void experienceNetworkLatency() {
int randomLatency = random(5, 10);
for (int i = 0; i < randomLatency; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
private void connectToServer(String server) {
System.out.print("Connecting to " + server + "... ");
experienceNetworkLatency();
System.out.print("Connected!" + "\n");
}
private HashMap<String, Video> getRandomVideos() {
System.out.print("Downloading populars... ");
experienceNetworkLatency();
HashMap<String, Video> hmap = new HashMap<String, Video>();
hmap.put("catzzzzzzzzz", new Video("sadgahasgdas", "Catzzzz.avi"));
hmap.put("mkafksangasj", new Video("mkafksangasj", "Dog play with ball.mp4"));
hmap.put("dancesvideoo", new Video("asdfas3ffasd", "Dancing video.mpq"));
hmap.put("dlsdk5jfslaf", new Video("dlsdk5jfslaf", "Barcelona vs RealM.mov"));
hmap.put("3sdfgsd1j333", new Video("3sdfgsd1j333", "Programing lesson#1.avi"));
System.out.print("Done!" + "\n");
return hmap;
}
private Video getSomeVideo(String videoId) {
System.out.print("Downloading video... ");
experienceNetworkLatency();
Video video = new Video(videoId, "Some video title");
System.out.print("Done!" + "\n");
return video;
}
}
package com.exam.proxydemo.proxy;
import com.exam.proxydemo.domain.Video;
import com.exam.proxydemo.service.ThirdPartyYoutubeClass;
import com.exam.proxydemo.service.ThirdPartyYoutubeLib;
import java.util.HashMap;
/**캐싱 프록시 */
public class YoutubeCacheProxy implements ThirdPartyYoutubeLib {
private ThirdPartyYoutubeLib youtubeService;
private HashMap<String, Video> cachePopular = new HashMap<String, Video>();
private HashMap<String, Video> cacheAll = new HashMap<String, Video>();
/**프록시 객체를 생성할 때 서비스 인터페이스 타입으로 서비스 객체 생성 */
public YoutubeCacheProxy() {
this.youtubeService = new ThirdPartyYoutubeClass();
}
@Override
public HashMap<String, Video> popularVideos() {
if (cachePopular.isEmpty()) {
cachePopular = youtubeService.popularVideos();
} else {
System.out.println("Retrieved list from cache.");
}
return cachePopular;
}
@Override
public Video getVideo(String videoId) {
Video video = cacheAll.get(videoId);
if (video == null) {
video = youtubeService.getVideo(videoId);
cacheAll.put(videoId, video);
} else {
System.out.println("Retrieved video '" + videoId + "' from cache.");
}
return video;
}
public void reset() {
cachePopular.clear();
cacheAll.clear();
}
}
'공부 > Java' 카테고리의 다른 글
JUnit test 메소드 실행 순서 설정 (0) | 2019.12.23 |
---|---|
QueryDSL 간단 예제(1) - select, update (2) | 2019.12.18 |
Hibernate(10) - 응용 문법 ② (엔티티 직접 사용, named 쿼리, 벌크연산) (0) | 2019.11.26 |
Hibernate(9) - 응용 문법 ① (경로 표현식, 페치 조인, 다형성 쿼리) (0) | 2019.11.26 |
Hibernate(8) - 객체지향 쿼리 언어(JPQL, QueryDSL 등) (0) | 2019.11.25 |