자바 의 프 록 시 동적 에이전트

1.Jvm 로 딩 대상
자바 동적 대 리 를 말 하기 전에 Jvm 로 딩 대상 의 과정 을 말 해 야 합 니 다.이것 은 동적 대 리 를 이해 하 는 기본 적 인 원리 입 니 다.

자바 류 는 소스 코드 프로그램.java형식 파일 로 컴 파일 러 를 통 해 컴 파일 된 후에 바이트 코드.class형식 파일 로 바 뀌 었 습 니 다.클래스 로 더 는 바이트 코드 를 읽 고 자바.lang.Class 대상 으로 바 뀌 었 습 니 다.메타 데이터 공간 에 있 는 데이터 구 조 를 설명 하고 클래스 가 예화 되 었 을 때 더미 에 예화 된 대상 정 보 를 저장 합 니 다.또한 대상 형식 데이터 의 지침 을 통 해 클래스 를 찾 습 니 다.
프로 세 스 설명:원본->.자바 파일->.class 파일->Class 대상->인 스 턴 스 대상
그래서 New 창설 대상 을 통 해 그 배후 에 많은 세부 사항 을 독단 하고 상술 한 과정 을 이해 한 후에 자주 사용 하 는 디자인 모델,즉 대리 모델 을 이해한다.
2.대리 모드
2.1 기본 설명
프 록 시 모드 는 특정한(목표)대상 에 게 프 록 시 대상 을 제공 하고 프 록 시 대상 이 대상 의 인용 을 가지 고 있 습 니 다.대리 란 한 대상 이 다른 대상 을 대표 하여 해당 하 는 동작 절 차 를 수행 하 는 것 이다.한편,대리 대상 은 클 라 이언 트 와 목표 대상 사이 에서 중개 역할 을 할 수 있다.

대리 모델 은 실제 생활 에서 장면 이 매우 많다.예 를 들 어 중개,변호사,대리 구 매 등 업 종 은 모두 간단 한 대리 논리 로 이 모델 에서 두 가지 관건 적 인 역할 이 존재 한다.
대상 역할:즉 대리 대상 이 대표 하 는 대상 입 니 다.
대리 대상 역할:내부 에 목표 대상 의 인용 이 포함 되 어 있 고 목표 대상 을 조작 할 수 있 습 니 다.AOP 프로 그래 밍 은 바로 이 사상 에 기초 한 것 이다.
2.2 정적 모드
  • 정적 에이전트:프로그램 이 실행 되 기 전에 에이전트 역할 을 확정 하고 에이전트 클래스 와 목표 클래스 의 관 계 를 명 확 히 합 니 다.
  • 동적 에이전트:자바 반사 체 제 를 바탕 으로 JVM 이 실 행 될 때 동적 으로 프 록 시 대상 을 만 들 고 생 성 합 니 다.
  • 3.정적 에이전트
    상기 정적 에이전트 의 개념 을 바탕 으로 코드 로 설명 하여 실현 합 니 다.기본 논 리 는 다음 과 같 습 니 다.
  • 목표 대상 이 대리 대상 임 을 명 확 히 한다.
  • 대리 대상 을 정의 하고 구조 기 를 통 해 목표 대상 을 가진다.
  • 대리 대상 에서 앞 뒤 강화 방법 을 정의 합 니 다.
  • 목표 대상 과 앞 뒤 강화 코드 를 설치 하면 대리 대상 을 구성 합 니 다.그러면 목표 대상 을 직접 방문 하지 않 아 도 됩 니 다.마치 드라마 에서 말 한 것 처럼 저 는 변호사 입 니 다.제 당사자 가 당신 과 대화 하기 가 불편 합 니 다.
    
    public class Proxy01 {
        public static void main(String[] args) {
            TargetObj targetObj = new TargetObj() ;
            ProxyObj proxyObj = new ProxyObj(targetObj) ;
            proxyObj.invoke();
        }
    }
    class TargetObj {
        public void execute (){
            System.out.println("       ...");
        }
    }
    class ProxyObj {
        private TargetObj targetObj ;
        /**
         *       
         */
        public ProxyObj (TargetObj targetObj){
            this.targetObj = targetObj ;
        }
        /**
         *         
         */
        public void invoke (){
            before () ;
            targetObj.execute();
            after () ;
        }
        /**
         *      
         */
        public void before (){
            System.out.println("        ...");
        }
        public void after (){
            System.out.println("        ...");
        }
    }
    정적 프 록 시 는 프 록 시 대상,즉 하나의 프 록 시 대상.java파일 을 JVM 에 불 러 오 는 과정 을 명확 하 게 정의 했다.분명 한 문 제 는 실제 개발 과정 에서 모든 목표 대상 에 게 하나의 프 록 시 클래스 를 정의 할 수 없고 한 대리 대상 이 여러 목표 대상 을 대리 하 게 할 수 없다.이 두 가지 방식 의 유지 비용 이 매우 높다.
    프 록 시 모델 의 본질은 목표 대상 의 방법 전후 에 증강 작업 을 하 는 것 이지 만 목표 류 를 수정 하고 싶 지 않다.앞의 반사 체 제 를 통 해 알 수 있 듯 이 운행 할 때 대상 의 구조 정 보 를 얻 을 수 있 고 Class 정 보 를 바탕 으로 프 록 시 대상 을 동적 으로 만 드 는 것 이 바로 동적 프 록 시 체제 이다.
    참고 로 기술 의 밑바닥 실현 논리 가 이해 하기 어 려 운 것 은 잘 알려 져 있 지만 기초 지식 점 은 복잡 하지 않다.예 를 들 어 대리 모델 의 기본 원리 이지 만 실제 복잡 한 응용(AOP 모델)과 결합 하면 반사 와 동태 대 리 를 바탕 으로 하 는 방식 으로 이 루어 진 것 이 라 고 생생 하 게 이해 하기 어렵다.
    동적 에이전트
    4.1 장면 묘사
    한 장면 을 바탕 으로 동태 대리 와 정태 대리 의 차 이 를 묘사 합 니 다.즉,최근 몇 년 동안 핫 한 개념,해외 대리 구 매:

    대리 구 매가 막 일어 난 초기 에는 해외 출장 을 자주 가 는 사람들 이 대리 구 매 수 요 를 받는다.즉,대리인 이 고정한다.그 후에 해외 대리 구 매 플랫폼,해 타 오 등 일련의 제품 이 유행 했다.즉,사용자 대리 구 매 수요(목표 대상)는 대리 구 매 플랫폼 에서 이 루어 졌 다.그러나 구체 적 으로 누가 이 를 조작 하 는 지 는 실시 간 분 배 를 보면 이 장면 은 동태 대리 의 원리 와 유사 하 다.
    4.2 기초 API 사례
    먼저 두 가지 핵심 유형 을 살 펴 보고 여기 서 개념 을 약술 하고 기본 과정 을 보고 다시 자세하게 이야기 합 니 다.
    프 록 시-프 록 시 대상 생 성,핵심 매개 변수:
  • ClassLoader:(대상 클래스)로 더;
  • 인터페이스:(목표 클래스)인터페이스 배열;
  • InvocationHandler:대리 호출 메커니즘;
  • Invocation Handler-에이전트 호출 메커니즘:
  • invoke:이 전편 에서 말 한 반사 원리;
  • method:반사 라 이브 러 리 의 핵심 API;
  • 대상 과 인터페이스
    
    interface IUser {
        Integer update (String name) ;
    }
    class UserService implements IUser {
        @Override
        public Integer update(String name) {
            Integer userId = 99 ;
            System.out.println("UserId="+userId+";updateName="+name);
            return userId ;
        }
    }
    에이전트 개체 실행 메커니즘
    
    class UserHandler implements InvocationHandler {
        private Object target ;
        public UserHandler (Object target){
            this.target = target ;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("before()...");
            Object result = method.invoke(target, args);
            System.out.println("after()...");
            return result;
        }
    }
    구체 적 인 조합 방식
    
    public class Proxy02 {
        public static void main(String[] args) {
            /*
             *   $Proxy0 class  
             */
            System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
            /*
             *       
             */
            IUser userService = new UserService();
            ClassLoader classLoader = userService.getClass().getClassLoader();
            Class<?>[] interfaces = UserService.class.getInterfaces() ;
            /*
             *       
             */
            InvocationHandler userHandler = new UserHandler(userService);
            /*
             *       
             * proxyClassName=com.java.proxy.$Proxy0
             */
            String proxyClassName = Proxy.newProxyInstance(classLoader,interfaces,userHandler).getClass().getName();
            System.out.println("proxyClassName="+proxyClassName);
            /*
             *         
             */
            IUser proxyUser1 = (IUser) Proxy.newProxyInstance(classLoader,interfaces,userHandler);
            IUser proxyUser2 = (IUser) Proxy.newProxyInstance(classLoader,interfaces,userHandler);
            proxyUser1.update("cicada") ;
            proxyUser2.update("smile") ;
        }
    }
    여기 서 프 록 시 클래스 의 구조 정 보 를 생 성 하려 는 이 유 는 JVM 로 딩 과정 에서 관련 내용 을 볼 수 없 기 때문에 관건 적 인 정 보 는 다시 독단 되 었 습 니 다.
    javap -v Proxy02.class

    프 록 시 클래스 이름 보기
    
    /*
     * proxyClassName=com.java.proxy.$Proxy0
     */
    String proxyClassName = Proxy.newProxyInstance(classLoader,interfaces,userHandler).getClass().getName();
    System.out.println("proxyClassName="+proxyClassName);
    무의식 출력 에이전트 의 대상 이름 입 니 다.여 기 는 JVM 체제 에 대응 하여 Class 대상 이름 을 찾 은 다음 에 구 조 를 분석 하면 동적 에이전트 의 구체 적 인 집행 원 리 를 알 수 있 습 니 다.
    프 록 시 클래스.class 파일 생 성
    
    System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
    위의 JVM 로 딩 대상 체 제 를 통 해 알 수 있 듯 이 프 록 시 클래스 를 설명 하 는 Class 대상 은 반드시 존재 합 니 다.실행 할 때 명시 적.class파일 이 생 성 되 지 않 았 을 뿐 프 록 시 클래스.class문법 을 통 해 프로젝트 디 렉 터 리/com/java/proxy경로 에서 파일 을 만 듭 니 다.
    참고 로 프로그래머 로 서 복잡 함 은 항상 우리 와 둘러싸 여 있 습 니 다.간단하게 말씀 해 주 시 겠 습 니까?
    4.3 대리 류 구조
    계승 과 실현
    
    class $Proxy0 extends Proxy implements IUser {}
    대리 류 의 기능 을 생각해 보면 Proxy 를 계승 하고 IUser 인 터 페 이 스 를 실현 해 야 한 다 는 것 을 알 수 있다.그리고 호출 체 제 를 가 진 구체 적 인 실현 류 를 가지 고 업무 강화 에 사용 해 야 한다.
    구조 방법
    
    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }
    구조 적 방법 을 통 해 UserHandler 의 구체 적 인 집행 메커니즘 대상 을 가지 고 있다.
    인터페이스 구현
    
    final class $Proxy0 extends Proxy implements IUser {
        private static Method m3;
        public final Integer update(String var1) throws  {
            try {
                return (Integer)super.h.invoke(this, m3, new Object[]{var1});
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
    }
    목표 류 의 기본 수요update()방법 은 대리 류 를 통 해 인수 하고 UserHandler 를 바탕 으로 구체 적 인 증강 업무 처 리 를 실현 한다.
    기초 방법
    
    final class $Proxy0 extends Proxy implements IUser {
        private static Method m0;
        private static Method m1;
        private static Method m2;
        public $Proxy0(InvocationHandler var1) throws  {
            super(var1);
        }
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m3 = Class.forName("com.java.proxy.IUser").getMethod("update", Class.forName("java.lang.String"));
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
        public final boolean equals(Object var1) throws  {
            try {
                return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
        public final String toString() throws  {
            try {
                return (String)super.h.invoke(this, m2, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
        public final int hashCode() throws  {
            try {
                return (Integer)super.h.invoke(this, m0, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    }
    Object 클래스 를 바탕 으로 자바 에서 자주 사용 되 는 방법 인 equals()판단,toString()방법,hashCode()값 을 정의 합 니 다.이것 은 Map 소스 코드 를 분석 할 때 왜 이 몇 가지 방법 이 함께 나타 나 는 지 말 한 적 이 있 습 니 다.
    4.4,JDK 소스 코드
    위 는 사례 수행 의 과정 과 원리 이 고 또 하나의 관건 적 인 점 은 JDK 소스 코드 의 논리 이다.
    
    IUser proxyUser = (IUser) Proxy.newProxyInstance(classLoader,interfaces,userHandler);
    Proxy 가 제공 하 는 정적 방법newProxyInstance()은 각 매개 변수의 입력 을 통 해 새로운 프 록 시 Class 대상,즉$Proxy 0 류 의 구조 정 보 를 구축 합 니 다.여기 서 다음 세 가지 핵심 매개 변 수 를 다시 살 펴 보 겠 습 니 다.
  • ClassLoader:JVM 실행 과정 을 바탕 으로 대상 클래스 UserService 의 클래스 로 더 를 가 져 와 야 합 니 다.
  • 인터페이스:목표 류 UserService 가 실현 하 는 인 터 페 이 스 는 대상 을 대상 으로 인터페이스 와 분 리 를 고려 하고 대리 류 는 IUser 인 터 페 이 스 를 실현 하여 목표 류 의 수 요 를 모 의 한다.
  • Invocation Handler:대리 류 가 제공 하 는 기능 패 키 징 즉 UserHandler 는 목표 방법 호출 전후 에 강화 처 리 를 할 수 있 습 니 다.
  • 마지막 으로 동적 대리 의 실현 의 핵심 기술 점 을 요약 한다.Jvm 로드 원리,반사 체제,대상 을 대상 으로 하 는 사상 이다.JDK 의 소스 코드 를 읽 을 때마다 디자이너 의 정교 함 에 경탄 하고 물방울 이 돌 을 뚫 고 버 텨 야 얻 을 수 있다.
    5.소스 코드 주소
    GitHub/주소
    https://github.com/cicadasmile/java-base-parent
    GitEE/주소
    https://gitee.com/cicadasmile/java-base-parent
    이상 은 자바 의 프 록 시 동적 프 록 시 메커니즘 에 대한 상세 한 내용 입 니 다.자바 프 록 시 동적 프 록 시 메커니즘 에 관 한 자 료 는 다른 관련 글 을 주목 하 십시오!

    좋은 웹페이지 즐겨찾기