자바 동적 프로 그래 밍 초기 분석

8580 단어 assist자바대리
더 읽 기
자바 에이전트 기술 - 아 리 면접 및 에이전트 인 스 턴 스:https://www.cnblogs.com/aspirant/p/8796974.html
 
자바 에이전트 초기 탐색 및 assist 인 스 턴 스 결합:https://www.jianshu.com/p/b2d09a78678d
 
자바 동적 프로 그래 밍 초기 탐색 - Javassist
 
최근 에는 코드 생 성 설정 을 통 해 중복 인 코딩 과 유지 비용 을 줄 여야 합 니 다.동태 적 인 특성 을 사용 하여 여러분 과 소감 을 나 누 었 습 니 다.
우리 가 자주 사용 하 는 동적 특성 은 주로 반사 입 니 다. 실행 할 때 대상 속성, 방법 을 찾 고 역할 도 메 인 을 수정 하 며 방법 이름 호출 방법 등 을 사용 합 니 다.온라인 의 응용 은 반사 성능 비용 이 비교적 많 기 때문에 자주 반 사 를 사용 하지 않 을 것 이다.사실 반사 와 같은 강력 한 특성 도 있 지만 씀 씀 이 는 매우 낮다. 그것 이 바로 자바 ssit 이다.
자바 ssit 는 사실 두 개의 패키지 로 실행 할 때 자바 바이트 코드 를 조작 하 는 방법 을 제공 합 니 다.자바 코드 를 컴 파일 하면 'class 파일' 이 생 성 되 는 바이트 코드 라 는 것 을 잘 알 고 있 습 니 다.JVM (정확히 말 하면 JIT) 은 이 바이트 코드 (기계 코드 로 변환 하고 실행) 를 실행 하 는 것 을 설명 할 것 입 니 다. 바이트 코드 의 해석 이 실 행 될 때 진행 되 기 때문에 바이트 코드 를 손 으로 작성 하고 JVM 에서 실행 할 수 있 습 니까?답 은 긍정 적 이 고 자바 시 스 트 는 이러한 방법 을 통 해 바이트 코드 를 만 들 수 있 는 편리 한 방법 을 제공 했다.
바이트 코드 와 같은 조작 방법 은 ASM 도 있다.몇 가지 동적 프로 그래 밍 방법 을 비교 하면 성능 에 있어 서 자바 ssist 는 반사 보다 높 지만 ASM 보다 낮다. 왜냐하면 자바 ssist 는 추상 을 증가 시 켰 기 때문이다.실현 원가 에 있어 서 자바 ssist 와 반사 가 매우 낮 고 ASM 은 바이트 코드 를 직접 조작 하기 때문에 자바 ssist 소스 코드 등급 의 api 에 비해 실현 원가 가 매우 높다.몇 가지 방법 은 자신 만 의 응용 장면 이 있 는데 예 를 들 어 Kryo 는 ASM 을 사용 하여 성능 의 최대 화 를 추구한다.한편, NBean CopyUtil 은 자바 ssist 를 사용 하여 대상 복사 의 성능 도 다른 라 이브 러 리 보다 현저히 높 고 용이 성 을 유지 했다.실제 프로젝트 에 서 는 먼저 자바 ssist 로 원형 을 실현 하 는 것 을 추천 합 니 다. 만약 성능 테스트 에서 자바 ssist 가 성능 병목 이 된 것 을 발견 하면 다른 바이트 코드 조작 방법 을 사용 하여 최적화 하 는 것 을 고려 합 니 다.
Javassist 의 사용 은 간단 합 니 다. 먼저 class 가 정의 하 는 용기 ClassPool 을 가 져 옵 니 다. 컴 파일 된 클래스 (Compile time class) 를 가 져 오고 이 클래스 에 부모 클래스 를 설정 합 니 다. writeFile 은 이 클래스 의 정 의 를 나중에 사용 할 수 있 도록 디스크 에 새로 쓰 도록 합 니 다.
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("test.Rectangle");
cc.setSuperclass(pool.get("test.Point"));
cc.writeFile();

CtClass 에서 편리 하 게 바이트 코드 를 가 져 오고 바이트 코드 를 불 러 올 수 있 습 니 다.
byte[] b = cc.toBytecode();
Class clazz = cc.toClass();

새로운 종 류 를 정의 하려 면
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("Point");

마찬가지 로 CtMethod 와 CtField 구조 방법 과 멤버, 심지어 Annotation 을 통 해 도 가능 하 다.
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("foo");
CtMethod mthd = CtNewMethod.make("public Integer getInteger() { return null; }", cc);
cc.addMethod(mthd);
CtField f = new CtField(CtClass.intType, "i", cc);
point.addField(f);
clazz = cc.toClass(); Object instance = class.newInstance();

Javassist 는 클래스, 변수 와 방법 을 생 성 할 수 있 을 뿐만 아니 라 기 존의 방법 도 조작 할 수 있 습 니 다. 이것 은 AOP 에서 매우 유용 합 니 다. 예 를 들 어 방법 호출 의 매장 점 등 입 니 다.
// Point.java
class Point {
    int x, y;
    void move(int dx, int dy) { x += dx; y += dy; }
}

//        move      
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("Point");
CtMethod m = cc.getDeclaredMethod("move");
m.insertBefore("{ System.out.println($1); System.out.println($2); }");
cc.writeFile();

그 중에서 $1 과 $2 는 스 택 의 첫 번 째 와 두 번 째 인 자 를 호출 하고 디스크 에 쓴 class 정의 가 유사 합 니 다.
class Point {
    int x, y;
    void move(int dx, int dy) {
        { System.out.println(dx); System.out.println(dy); }
        x += dx; y += dy;
    }
}

자바 ssist 를 사용 할 때 문제 가 있 었 습 니 다.
1. tomcat 와 jboss 는 독립 된 classloader 를 사용 하기 때문에 자바 ssist 는 기본 classloader 를 통 해 클래스 를 불 러 옵 니 다. 따라서 tomcat context 에서 정 의 된 클래스 를 toClass 로 직접 사용 하면 ClassCastException 이상 을 던 지고 tomcat 의 classloader 로 바이트 코드 를 불 러 올 수 있 습 니 다.
CtClass cc = ...;
Class c = cc.toClass(bean.getClass().getClassLoader());

2. 간단 한 테스트 에서 load 할 수 있 는 종 류 를 발 견 했 습 니 다. tomcat 에 서 는 load 할 수 없습니다.Classpool. getDefault () 가 찾 은 경로 와 아래쪽 JVM 경로 때문이다.tomcat 에 서 는 여러 개의 classloader 를 정의 하기 때문에 추가 적 인 class 경 로 는 ClassPool 에 등록 해 야 합 니 다.
pool.insertClassPath(new ClassClassPath(this.getClass()));

3. 실행 할 때 클래스 를 수정 하 는 방법 을 원 하지만 JVM 은 동적 인 reload 류 정 의 를 허용 하지 않 습 니 다.classloader 가 class 를 불 러 오 면 이 class 의 다른 버 전 을 다시 불 러 올 수 없습니다. toClass () 를 호출 하면 LinkageError 를 던 집 니 다.따라서 이러한 방식 으로 새로운 클 라 스 를 정의 해 야 한다.toClass () 는 현재 thread 가 있 는 classloader 로 class 를 불 러 옵 니 다.
4. 자바 ssist 에서 생 성 된 바이트 코드 는 class 성명 이 없 기 때문에 바이트 코드 생 성 변수 와 방법 호출 은 모두 반 사 를 통 해 이 루어 져 야 합 니 다.이 점 은 온라인 응용 에서 의 성능 손실 은 받 아들 일 수 없다. NBeanCopyUtil 이 실현 한 시사 점 을 받 아 인터페이스, 자바 ssist 의 바이트 코드 를 정의 하여 이 인 터 페 이 스 를 실현 할 수 있다. 호출 자 는 이 인 터 페 이 스 를 통 해 바이트 코드 를 반사 하 는 것 이 아니 라 반사 호출 비용 을 피 할 수 있다.또 하나의 바이트 코드 new 변수 도 반 사 를 통 해 반사 되 기 때문에 프 록 시 방법 을 통 해 pv 마다 new 가 필요 한 바이트 코드 대상 을 매번 new 프 록 시 대상 으로 바 꾸 고 메모리 에 상주 하 는 바이트 코드 대상 에 대리 하여 매번 반 사 된 비용 을 피 할 수 있 습 니 다.
참고 자료:
http://asm.ow2.org/
http://notatube.blogspot.com/2010/11/project-lombok-trick-explained.html
http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/tutorial/tutorial.html
http://www.ibm.com/developerworks/cn/java/coretech/java-dynamic.html

좋은 웹페이지 즐겨찾기