자바 디자인 모드 의 프 록 시 모드 상세 설명
대리 모델 은 장 삼 이 하나 있 는데 다른 사람 은 그 를 찾 을 방법 이 없고 그의 비서 만 이 그 를 찾 을 수 있다.그 다른 사람들 은 장 삼 과 상호작용 을 하려 면 그의 비 서 를 통 해 전달 과 상호작용 을 할 수 밖 에 없다.이 비 서 는 바로 대리자 이 고,그 는 장 삼 을 대리 한다.
집 을 팔다
집 을 파 는 절차:
1.바 이 어 를 찾는다
2.가격 협상
3.계약 체결
4.부동산 국 과 난잡 한 양도 협 의 를 체결한다
일반적으로 판매 자 는 계약 을 할 때 만 나 설 수 있 고,다른 1,2,4 는 모두 중개 가 한다.그럼 물 어보 면 뭐 해?
우선,한 중개인 은 여러 명의 집 을 파 는 판매 자 를 대리 할 수 있다.그 다음 에 우 리 는 판매자 의 코드 를 수정 하지 않 은 상황 에서 그 에 게 집 값 을 올 리 고 광 고 를 하 는 등 밀수품 을 끼 우 는 기능 을 실현 할 수 있다.
자바 의 프 록 시 모드 는 정적 에이전트 와 동적 에이전트 로 나 뉜 다.
정적 에이전트
정적 에이전트 에 다음 과 같은 역할 이 존재 합 니 다:
// ( )
public interface Singer{
//
void sing();
}
남자 가수
// ,
public class MaleSinger implements Singer{
private String name;
public MaleSinger(String name) {
this.name = name;
}
@Override
public void sing() {
System.out.println(this.name+" ");
}
}
가수 의 매니저
//
public class Agent implements Singer{
private MaleSinger singer; //
public Agent(MaleSinger singer) {
this.singer = singer;
}
@Override
public void sing() {
System.out.println(" , ");
//
singer.sing();
System.out.println(" , ");
}
}
거래처
//
public class Client {
public static void main(String[] args) {
MaleSinger singer=new MaleSinger(" ");
Agent agent=new Agent(singer);
agent.sing();//
}
}
추상 적 인 캐릭터 를 보면 구체 적 인 캐릭터 와 대리 캐릭터 의 공공 적 인 방법 인 sing()을 포함한다.그리고 가수 의 매니저 를 통 해 가수 가 노래 를 부 르 는 전후 에 자신 이 추가 하고 싶 은 코드 를 임의로 추가 할 수 있다.가수 류 방법 을 고치 지 않 고 노래 에 새로운 기능 을 추가 하 는 목적 을 달성 했다.솔직히 말 하면프 록 시 는 원래 의 코드 를 수정 하지 않 은 상태 에서 소스 코드 에 기능 을 강화 하 는 것 이다.
작은 매듭
정적 프 록 시 모드 의 주요 장점 은:
그 주요 단점 은:
3.동적 에이전트
정적 에이전트 에서 예 를 들 어 상기 한 예 를 들 어 우리 가 쓴 매니저 는 malesinger 만 서비스 할 수 있 고 다른 유형의 가수 에 게 더 이상 서 비 스 를 제공 할 수 없다 는 것 은 비 현실 적 이다.매니저 가 서 비 스 를 받 을 수 있 는 것 은 한 가수 가 아니 라 가수 도 아 닌 서비스 로 춤 을 추 러 갈 수 있 기 때문이다.정적 에이전트 에서 이 결 과 를 실현 하려 면 여러 개의 에이전트 류 를 수 동 으로 작성 해 야 합 니 다.매우 번 거 롭 고 복잡 합 니 다.그래서 동적 에이전트 가 나 타 났 습 니 다.동적 대 리 는 대리인의 코드 를 자동 으로 생 성 할 수 있 습 니 다.
JDK 원생 의 동적 에이전트
핵심 클래스:
InvocationHandler
와Proxy
우 리 는 Singer 인 터 페 이 스 를 다시 써 서 그 에 게 춤 추 는 방법 을 하나 더 주 었 다.
//
public interface Singer2 {
void sing();
void dance();
}
물론 그 에 대응 하 는 남자 가수 의 실현 유형 도 바 뀌 어야 한다.
//
public class MaleSinger2 implements Singer2 {
private String name;
public MaleSinger2(String name) {
this.name = name;
}
@Override
public void sing() {
System.out.println(this.name+" ");
}
@Override
public void dance() {
System.out.println(this.name+" ");
}
}
그런 후에 우 리 는 직접 고객 에 게 들 어가 테스트 를 한다.
import com.hj.Agent2;
import com.hj.MaleSinger2;
import com.hj.Singer2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Client2 {
public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");// jdk
// ,
System.out.println(" 1------------------------------------------------");
MaleSinger2 maleSinger = new MaleSinger2(" ");
//
//newProxyInstance(ClassLoader loader, , https://blog.csdn.net/Doraemon_Nobita/article/details/115702012?spm=1001.2014.3001.5501
//Class<?>[] interfaces, ,
//InvocationHandler h )
Singer2 agent = (Singer2) Proxy.newProxyInstance(Client2.class.getClassLoader(),
new Class[]{Singer2.class}, new InvocationHandler() {// InvocationHandler , https://blog.csdn.net/Doraemon_Nobita/article/details/115506705?spm=1001.2014.3001.5501
@Override
// invoke agent.sing()
// invoke(Object proxy,
// Method method, method , ( , sing() dance())
// Object[] args , )
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(" , ");
// invoke , :https://blog.csdn.net/Doraemon_Nobita/article/details/115702012?spm=1001.2014.3001.5501 。
//invoke , Object , ,
// , , args ,
Object invoke = method.invoke(maleSinger,args);// method invoke , 。 maleSinger
System.out.println(" , ");
return invoke;
}
});
agent.sing();// maleSinger sing()
agent.dance();// maleSinger dance()
System.out.println(" 2------------------------------------------------");
// , maleSinger, 。 。
// InvocationHandler , Agent2
MaleSinger2 JayZ=new MaleSinger2(" ");
MaleSinger2 JJ =new MaleSinger2(" ");
Singer2 agentJJ=(Singer2) Proxy.newProxyInstance(Client2.class.getClassLoader(),
new Class[]{Singer2.class}, new Agent2(JJ));
Singer2 agentJayZ=(Singer2) Proxy.newProxyInstance(Client2.class.getClassLoader(),
new Class[]{Singer2.class}, new Agent2(JayZ));
//
agentJJ.dance();
agentJJ.sing();
agentJayZ.sing();
agentJayZ.dance();
}
}
첫 번 째 예 에서 프 록 시 클래스 의 new Proxy Instance()방법 을 이용 하면 프 록 시 대상 을 만 들 수 있 습 니 다.한편,new Proxy Instance()의 매개 변 수 는 클래스 로 더,실 현 된 인터페이스 배열,그리고 Invocation Handler 대상 이 있다.여기 서 익명 의 내부 클래스 를 사용 하여 Invocation Handler 인 터 페 이 스 를 실현 합 니 다.이 인 터 페 이 스 를 실현 하려 면 그의 invoke 방법 을 실현 해 야 한다.이 방법 은 바로 우리 대리 대상 이 원래 의 방법 을 호출 할 때 사용 하 는 방법 이다.반사 중의 invoke 방법 과 달리 세 개의 매개 변 수 는 대리 대상,호출 방법,방법의 매개 변수 배열 이다.여기 서 대리 대상 은 우리 가 상관 하지 않 습 니 다.호출 방법 은 반 사 를 통 해 얻 은 우리 가 이 대리 호출 sing()방법 이나 dance()방법 을 사용 하 는 방법 입 니 다.반사 중인 invoke 방법 을 통 해 지정 한 대상 의 방법 명 을 실행 할 수 있 습 니 다.두 번 째 예 에서 모든 종 류 를 대리 할 수 있 도록 저 희 는 Invocation Handler 인 터 페 이 스 를 실현 하고 에이전트 2 라 고 부 릅 니 다.다음은 에이전트 2 코드 입 니 다.
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class Agent2 implements InvocationHandler {
private Object object;// ,
public Agent2(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(" , ");
//
Object invoke = method.invoke(object,args);
System.out.println(" , ");
return invoke;
}
}
이 를 통 해 알 수 있 듯 이 여기 서 첫 번 째 사례 의 실현 과 차이 가 많 지 않다.다만 우 리 는 Object 류 를 사용 하여 기 존의 죽음 을 쓴 Male Singer 류 를 대체 했다.그러면 우 리 는 모든 유형 을 대리 할 수 있다.이 유형 이 우리 가 앞 뒤로'협상 출연료,회의장 업무','회의장 정리,비용 결제'를 추가 해 야 한다.두 번 째 예 에서 임 준걸 과 주걸륜 의 대리인 은 쉽게 만 들 수 있 고 나중에 Female Singer 류 를 하나 더 실현 하 더 라 도 그의 대리인 을 직접 만 들 수 있다.더 하 다
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");// jdk
이 코드 를 사용 하면 프로젝트 에서 JDK 가 자동 으로 생 성 하 는 프 록 시 코드 를 찾 을 수 있 습 니 다.열 면 자동 으로 생 성 되 는 프 록 시 를 써 주 는 방법 입 니 다.
보 이 는 것 은 h.invoke 를 호출 한 것 입 니 다.이 h 는 바로 우리 가 Invocation Handler 로 전 달 된 대상 입 니 다.우리 가 쓴 invoke 방법 을 호출 했 습 니 다.
cglib 동적 에이전트
Maven 설정 파일 에서 해당 하 는 가방 을 가 져 와 야 합 니 다.pom.xml 파일 에 다음 코드 를 추가 합 니 다:
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>
사용 방법 은 JDK 의 동적 에이전트 와 유사 합 니 다.다만 우 리 는 더 이상 인 터 페 이 스 를 실현 할 필요 가 없습니다.일반 클래스 Cglib Male Singer.자바 를 정의 합 니 다.
public class CglibMaleSinger {
public CglibMaleSinger(String name) {
this.name = name;
}
private String name;
public CglibMaleSinger() {// , Superclass has no null constructors but no arguments were given
}
public void sing(){
System.out.println(this.name+" ");
}
public void dance(){
System.out.println(this.name+" ");
}
}
그리고 클 라 이언 트 에서 직접 테스트:
import com.hj.CglibMaleSinger;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibClient {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"./class");// class ,"./class" class
CglibMaleSinger JayZ=new CglibMaleSinger(" ");
Enhancer enhancer = new Enhancer();// enhancer
enhancer.setSuperclass(CglibMaleSinger.class);// ,
//MethodInterceptor ,
enhancer.setCallback(new MethodInterceptor() {//
// o ,
// method , ,
// objs
// methodProxy ( )
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(" ");
method.invoke(JayZ,objects);
System.out.println(" ");
return null;
}
});
CglibMaleSinger cglibMaleSinger = (CglibMaleSinger)enhancer.create();
cglibMaleSinger.sing();
cglibMaleSinger.dance();
}
}
JDK 의 동적 에이전트 사용 방법 과 거의 일치 합 니 다.invoke 방법 이 intercept 방법 으로 바 뀌 었 을 뿐 입 니 다.System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY," ");
문 구 를 추가 하면 자신 이 설정 한 저장 경로 에 생 성 된 class 파일 을 포함 하 는 폴 더 가 나타 납 니 다.hj 폴 더 의.class 파일 을 누 르 십시오.
우리 의 Cglib Male Singer 류 를 계승 하고 우리 의 방법 을 다시 썼 으 며,내용 을 다시 쓰 는 데 intercept()방법 을 사용 한 것 을 볼 수 있 습 니 다.
작은 매듭
자바 동적 프 록 시 는 인터페이스 에 만 프 록 시 를 할 수 있 고 일반 클래스 에 대해 서 는 프 록 시 를 할 수 없습니다.(모든 생 성 된 프 록 시 클래스 의 부모 클래스 는 Proxy 이 고 자바 가 다 중 계승 을 지원 하지 않 기 때 문 입 니 다)CGLIB 는 일반 클래스 자바 동적 프 록 시 를 대리 하여 자바 원생 의 반사 API 를 사용 하여 조작 할 수 있 으 며 생 성 클래스 에서 효율 적 입 니 다.CGLIB 는 ASM 프레임 워 크 를 사용 하여 바이트 코드(class)를 직접 바 꾸 었 기 때문에 자바 원생 보다 효율 적 으로 실 행 됩 니 다.
자바 디자인 모델 의 프 록 시 모델 에 대한 자세 한 설명 은 여기까지 입 니 다.더 많은 자바 프 록 시 모델 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.