javassist 사용 안내
1.Javassist 를 사용 하여 class 파일 만 들 기
우선 jar 가방 을 도입 해 야 합 니 다:
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.25.0-GA</version>
</dependency>
생 성 대상 의 클래스 작성:
package com.rickiyang.learn.javassist;
import javassist.*;
/**
* @author rickiyang
* @date 2019-08-06
* @Desc
*/
public class CreatePerson {
/**
* Person
*
* @throws Exception
*/
public static void createPseson() throws Exception {
ClassPool pool = ClassPool.getDefault();
// 1.
CtClass cc = pool.makeClass("com.rickiyang.learn.javassist.Person");
// 2. private String name;
// name
CtField param = new CtField(pool.get("java.lang.String"), "name", cc);
// private
param.setModifiers(Modifier.PRIVATE);
// "xiaoming"
cc.addField(param, CtField.Initializer.constant("xiaoming"));
// 3. getter、setter
cc.addMethod(CtNewMethod.setter("setName", param));
cc.addMethod(CtNewMethod.getter("getName", param));
// 4.
CtConstructor cons = new CtConstructor(new CtClass[]{}, cc);
cons.setBody("{name = \"xiaohong\";}");
cc.addConstructor(cons);
// 5.
cons = new CtConstructor(new CtClass[]{pool.get("java.lang.String")}, cc);
// $0=this / $1,$2,$3...
cons.setBody("{$0.name = $1;}");
cc.addConstructor(cons);
// 6. printName , , , name
CtMethod ctMethod = new CtMethod(CtClass.voidType, "printName", new CtClass[]{}, cc);
ctMethod.setModifiers(Modifier.PUBLIC);
ctMethod.setBody("{System.out.println(name);}");
cc.addMethod(ctMethod);
// .class
cc.writeFile("/Users/yangyue/workspace/springboot-learn/java-agent/src/main/java/");
}
public static void main(String[] args) {
try {
createPseson();
} catch (Exception e) {
e.printStackTrace();
}
}
}
위의 main 함 수 를 실행 하면 지정 한 디 렉 터 리 에 Person.class 파일 을 생 성 합 니 다.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.rickiyang.learn.javassist;
public class Person {
private String name = "xiaoming";
public void setName(String var1) {
this.name = var1;
}
public String getName() {
return this.name;
}
public Person() {
this.name = "xiaohong";
}
public Person(String var1) {
this.name = var1;
}
public void printName() {
System.out.println(this.name);
}
}
우리 가 예 상 했 던 것 과 같다.자바 ssist 에서 클래스
Javaassit.CtClass
는 class 파일 을 표시 합 니 다.GtClass(컴 파일 시 클래스)대상 은 class 파일 을 처리 할 수 있 습 니 다.ClassPool
대상 의 용기 입 니 다.이것 은 읽 기 클래스 파일 에 따라CtClass
대상 을 구성 하고 나중에 사용 할 수 있 도록CtClass
대상 을 저장 합 니 다.주의해 야 할 것 은 ClassPool 은 메모리 에서 생 성 된 모든 CtClass 를 유지 합 니 다.CtClass 의 수량 이 너무 많 을 때 대량의 메모 리 를 차지 합 니 다.API 에서 제 시 된 해결 방안 은 의식 적 으로 호출
CtClass
CtClass
방법 으로 메모 리 를 방출 합 니 다.ClassPool 이 주목 해 야 할 방법:
CtMethod 의 중요 한 방법:
//$0=this/$1,$2,$3...대표 적 인 방법 매개 변수
cons.setBody("{$0.name = $1;}");
구체 적 으로 많은 기 호 를 사용 할 수 있 지만 서로 다른 기 호 는 서로 다른 장면 에서 서로 다른 의 미 를 가지 기 때문에 여기 서 군말 하지 않 고 자바 ssist 의 설명 문 서 를 볼 수 있 습 니 다.http://www.javassist.org/tutorial/tutorial2.html
2.생 성 된 클래스 대상 호출
(1).반사 적 으로 호출
위의 사례 는 클래스 대상 을 만 들 고 이 대상 이 컴 파일 된 후의 class 파일 을 출력 하 는 것 입 니 다.그럼 우리 가 생 성 된 클래스 의 속성 이나 방법 을 호출 하려 면 어떻게 해 야 합 니까?javassist 도 해당 하 는 api 를 제공 합 니 다.클래스 대상 을 만 드 는 코드 는 첫 번 째 세그먼트 와 마찬가지 로 마지막 으로 파일 에 기록 한 코드 를 다음 과 같이 바 꿉 니 다.
// ,
Object person = cc.toClass().newInstance();
//
Method setName = person.getClass().getMethod("setName", String.class);
setName.invoke(person, "cunhua");
//
Method execute = person.getClass().getMethod("printName");
execute.invoke(person);
그리고 main 방법 을 실행 하면 printName 방법 을 호출 하 는 것 을 볼 수 있 습 니 다.(2).class 파일 을 읽 는 방식 으로 호출 합 니 다.
ClassPool pool = ClassPool.getDefault();
//
pool.appendClassPath("/Users/yangyue/workspace/springboot-learn/java-agent/src/main/java/");
CtClass ctClass = pool.get("com.rickiyang.learn.javassist.Person");
Object person = ctClass.toClass().newInstance();
// ......
(3).인 터 페 이 스 를 통과 하 는 방식위의 두 가 지 는 모두 반사 적 인 방식 으로 호출 된 것 이다.문 제 는 우리 의 공사 에 이런 대상 이 없 기 때문에 반사 하 는 방식 이 비교적 번 거 롭 고 비용 도 많이 든다.그러면 만약 에 당신 의 대상 이 일부 방법 으로 집합 할 수 있다 면 이런 유형 에 인터페이스 류 를 만 드 는 것 을 고려 할 수 있 습 니 다.이렇게 하면 new Instance()에서 우 리 는 인터페이스 로 강하 게 전환 할 수 있 고 반 사 된 세트 를 생략 할 수 있다.
위 에 있 는 Person 클래스 를 가지 고 PersonI 인터페이스 클래스 를 새로 만 듭 니 다.
package com.rickiyang.learn.javassist;
/**
* @author rickiyang
* @date 2019-08-07
* @Desc
*/
public interface PersonI {
void setName(String name);
String getName();
void printName();
}
실현 부분의 코드 는 다음 과 같다.
ClassPool pool = ClassPool.getDefault();
pool.appendClassPath("/Users/yangyue/workspace/springboot-learn/java-agent/src/main/java/");
//
CtClass codeClassI = pool.get("com.rickiyang.learn.javassist.PersonI");
//
CtClass ctClass = pool.get("com.rickiyang.learn.javassist.Person");
// , PersonI
ctClass.setInterfaces(new CtClass[]{codeClassI});
//
PersonI person = (PersonI)ctClass.toClass().newInstance();
System.out.println(person.getName());
person.setName("xiaolv");
person.printName();
사용 하기 편 해 요.3.기 존의 클래스 대상 수정
앞에서 말 했 듯 이 클래스 대상 을 추가 합 니 다.이 사용 장면 은 아직 만난 적 이 없 기 때문에 일반적으로 만 날 수 있 는 사용 장면 은 기 존의 유형 을 수정 해 야 한다.예 를 들 어 흔히 볼 수 있 는 로그 절단면,권한 절단면.우 리 는 javassist 를 이용 하여 이 기능 을 실현 한다.
다음 과 같은 대상 이 있 습 니 다.
package com.rickiyang.learn.javassist;
/**
* @author rickiyang
* @date 2019-08-07
* @Desc
*/
public class PersonService {
public void getPerson(){
System.out.println("get Person");
}
public void personFly(){
System.out.println("oh my god,I can fly");
}
}
그리고 그 를 수정 했다.
package com.rickiyang.learn.javassist;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import java.lang.reflect.Method;
/**
* @author rickiyang
* @date 2019-08-07
* @Desc
*/
public class UpdatePerson {
public static void update() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.rickiyang.learn.javassist.PersonService");
CtMethod personFly = cc.getDeclaredMethod("personFly");
personFly.insertBefore("System.out.println(\" \");");
personFly.insertAfter("System.out.println(\" 。。。。\");");
//
CtMethod ctMethod = new CtMethod(CtClass.voidType, "joinFriend", new CtClass[]{}, cc);
ctMethod.setModifiers(Modifier.PUBLIC);
ctMethod.setBody("{System.out.println(\"i want to be your friend\");}");
cc.addMethod(ctMethod);
Object person = cc.toClass().newInstance();
// personFly
Method personFlyMethod = person.getClass().getMethod("personFly");
personFlyMethod.invoke(person);
// joinFriend
Method execute = person.getClass().getMethod("joinFriend");
execute.invoke(person);
}
public static void main(String[] args) {
try {
update();
} catch (Exception e) {
e.printStackTrace();
}
}
}
detach()
방법 전후 에 인쇄 로 그 를 추가 하 였 습 니 다.그리고 하나의 방법personFly
을 추가 했다.main 함 수 를 실행 하면 이미 추 가 된 것 을 발견 할 수 있 습 니 다.또한 주의해 야 할 것 은 위의
joinFriend
와insertBefore()
의 문장 입 니 다.만약 당신 이 단행문 이 라면 쌍 따옴표 를 직접 사용 할 수 있 지만,여러 줄 의 문장 이 있 는 경우,여러 줄 의 문장 을{}로 묶 어야 합 니 다.javassist 는 하나의 문장 만 받 아들 이거 나 큰 괄호 로 묶 은 문장 블록 만 받 아들 입 니 다.이상 은 javassist 사용 안내서 의 상세 한 내용 입 니 다.javassist 사용 에 관 한 자 료 는 저희 의 다른 관련 글 을 주목 해 주 십시오!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
python 각종 excel 쓰기 방식의 속도 대비실험을 통해 새 excel 표를 만들었습니다. 이 표는 7개의sheet를 가지고 있으며, 각각sheet에는 800개의 데이터가 있으며, 그 중 마지막 sheet는 비어 있습니다. 먼저 openpyxl을 사용하여 쓰기...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.