자바 디자인 모드 의 프 록 시 모드 상세 설명

에이전트 모드
대리 모델 은 장 삼 이 하나 있 는데 다른 사람 은 그 를 찾 을 방법 이 없고 그의 비서 만 이 그 를 찾 을 수 있다.그 다른 사람들 은 장 삼 과 상호작용 을 하려 면 그의 비 서 를 통 해 전달 과 상호작용 을 할 수 밖 에 없다.이 비 서 는 바로 대리자 이 고,그 는 장 삼 을 대리 한다.
집 을 팔다
집 을 파 는 절차:
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)를 직접 바 꾸 었 기 때문에 자바 원생 보다 효율 적 으로 실 행 됩 니 다.
    자바 디자인 모델 의 프 록 시 모델 에 대한 자세 한 설명 은 여기까지 입 니 다.더 많은 자바 프 록 시 모델 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!
  • 좋은 웹페이지 즐겨찾기