자바 에이전트 입문 학습 의 동적 수정 코드

머리말
최근 오후 내 내 자바 에이 전 트 를 통 과 했 습 니 다.이 글 은 잊 혀 지지 않도록 구체 적 인 조작 절 차 를 기록 하 였 습 니 다.다음은 더 이상 말 하지 않 겠 습 니 다.상세 한 소 개 를 살 펴 보 겠 습 니 다.
자바 에이전트 를 통 해 코드(교체,수정 클래스 의 정의)를 동적 으로 수정 하여 AOP 를 진행 할 수 있 습 니 다.
목표:
@ToString 주 해 를 추가 하 는 모든 클래스 에 기본 toString 방법 을 구현 합 니 다. 
두 개의 프로그램 이 필요 합 니 다.하 나 는 테스트 용 프로그램 이 고,하 나 는 에이전트 가 코드 를 수정 하 는 데 사 용 됩 니 다.
1.테스트 프로그램
테스트 된 프로그램 포함:
  - ToString.Java
  - Foo.java
  - Main.java
구체 적 인 코드 는 다음 과 같다.
ToString.java:정의 ToString 주석

package com.chosen0ne.agent.test; 
 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
 
@Retention(RetentionPolicy.RUNTIME) 
public @interface ToString { 
} 
Foo.java:테스트 용 으로 간단하게 ToString 주 해 를 사 용 했 습 니 다.

package com.chosen0ne.agent.test; 
 
@ToString 
public class Foo { 
 
} 
Main.java:

package com.chosen0ne.agent.test; 
 
public class Main { 
 public static void main(String[] args) { 
  Foo foo = new Foo(); 
  System.out.println(foo.toString()); 
 } 
} 
Main.java 를 실행 한 결 과 는 다음 과 같 습 니 다.

com.chosen0ne.agent.test.Foo@7852e922
toString 이 Object 의 기본 구현 으로 돌아 오 는 것 을 볼 수 있 습 니 다.
2.에이전트 프로그램
자바 에이전트 프로그램 은 실제로 갈고리 와 유사 하 며 두 가지 방식 이 있 습 니 다.
  - main 함수 시작 전
  - 프로그램 실행 중
여 기 는 주로 main 함수 가 시작 되 기 전의 상황 을 테스트 합 니 다.main 함수 와 유사 하여 실현 이 필요 합 니 다.

public static void premain(String agentArgs, Instrumentation inst); 
이 함 수 는 main 함수 전에 호출 됩 니 다.premain 에서 바이트 코드 작업 을 하고 바 꾸 거나 클래스 를 다시 실현 할 수 있 습 니 다.이곳 은 Byte Buddy 라 이브 러 리 를 사용 하여 ASM 위 에 더욱 고 급 스 러 운 추상 을 제공 하여 사용 하기에 편리 하 다.
구체 적 인 코드 는 다음 과 같다.

package com.chosen0ne.ByteCode.agent; 
 
import java.lang.instrument.Instrumentation; 
 
import com.chosen0ne.agent.test.ToString; 
 
import net.bytebuddy.agent.builder.AgentBuilder; 
import net.bytebuddy.description.type.TypeDescription; 
import net.bytebuddy.dynamic.DynamicType.Builder; 
import net.bytebuddy.implementation.FixedValue; 
import net.bytebuddy.matcher.ElementMatchers; 
 
public class ToStringAgent { 
 
 public static void premain(String args, Instrumentation instrumentation) { 
  System.out.println("print pre main"); 
  new AgentBuilder.Default() 
    .type(ElementMatchers.isAnnotatedWith(ToString.class)) 
    .transform(new AgentBuilder.Transformer() { 
 
     @Override 
     public Builder<?> transform(Builder<?> builder, 
       TypeDescription typeDescription, ClassLoader classLoader) { 
      return builder.method(ElementMatchers.named("toString")) 
        .intercept(FixedValue.value("test")); 
     } 
      
    }).installOn(instrumentation); 
 } 
} 
에이전트 는 jar 로 포장 해 야 하 며,premain 방식 에 대해 서 는 MANIFEST.MF 에서 Premain-Class 를 지정 하여 premain 함 수 를 포함 하 는 클래스 를 표시 해 야 합 니 다.구체 적 으로 포장 하 는 방법 은 두 가지 가 있다.
 1)jar 명령 을 직접 통과
편집 하여 MANIFEST.MF 생 성 후 실행:

jar cvfm agent.jar MANIFEST.MF -C . com lib 
위 명령 으로 포 장 된 jar 포함:
  - com:컴 파일 생 성 된 class 파일
  - lib:의존 하 는 라 이브 러 리
 2)maven 을 통 해 직접 생 성:
maven-jar-plugin 플러그 인 을 통 해 jar 패 키 지 를 생 성 합 니 다.구체 적 인 설정 은 다음 과 같 습 니 다.

<build> 
 <plugins>  
  <plugin> 
   <groupId>org.apache.maven.plugins</groupId> 
   <artifactId>maven-jar-plugin</artifactId> 
   <version>2.1</version> 
   <configuration> 
    <archive> 
     <manifest> 
      <addClasspath>true</addClasspath> 
      <classpathPrefix>lib/</classpathPrefix> 
      <mainClass>com.chosen0ne.ByteCode.ByteBuddyTest</mainClass> 
     </manifest> 
     <manifestEntries> 
      <Premain-Class>com.chosen0ne.ByteCode.agent.ToStringAgent</Premain-Class> 
     </manifestEntries> 
    </archive> 
   </configuration> 
  </plugin> 
 </plugins> 
</build> 
주로 manifestEntries 탭 을 통 해 자동 속성 을 생 성 합 니 다.여 기 는 Premain-Class 를 지정 합 니 다.
3.운행
생 성 된 에이전트.jar,의존 하 는 ByteBuddy 의 jar 패키지 와 테스트 프로그램 컴 파일 로 생 성 된 class 파일 을 하나의 경로 에 놓 습 니 다.디 렉 터 리 레이아웃 은 다음 과 같 습 니 다.

. 
├── agent.jar 
├── classes 
│ └── com 
│  └── chosen0ne 
│   └── agent 
│    └── test 
│     ├── Foo.class 
│     ├── Main.class 
│     └── ToString.class 
└── lib 
 └── byte-buddy-1.2.3.jar 
현재 디 렉 터 리 에서 명령 실행:

java -cp classes:lib/byte-buddy-1.2.3.jar -javaagent:agent.jar com.chosen0ne.agent.test.Main 
실행 결 과 는 다음 과 같 습 니 다.

print pre main 
test 
테스트 프로그램 도 jar 패키지 로 포장 하면-cp 를 통 해 ByteBuddy 라 이브 러 리 를 지정 할 때 실패 합 니 다.대응 하 는 class 를 찾 을 수 없습니다.오 류 는 다음 과 같 습 니 다.

> java -cp classes:lib/byte-buddy-1.2.3.jar -javaagent:agent.jar -jar agent-test-case-0.0.1-SNAPSHOT.jar 
Exception in thread "main" java.lang.NoClassDefFoundError: net/bytebuddy/matcher/ElementMatcher 
 at java.lang.Class.getDeclaredMethods0(Native Method) 
 at java.lang.Class.privateGetDeclaredMethods(Class.java:2688) 
 at java.lang.Class.getDeclaredMethod(Class.java:2115) 
 at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:327) 
 at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:401) 
Caused by: java.lang.ClassNotFoundException: net.bytebuddy.matcher.ElementMatcher 
 at java.net.URLClassLoader$1.run(URLClassLoader.java:372) 
 at java.net.URLClassLoader$1.run(URLClassLoader.java:361) 
 at java.security.AccessController.doPrivileged(Native Method) 
 at java.net.URLClassLoader.findClass(URLClassLoader.java:360) 
 at java.lang.ClassLoader.loadClass(ClassLoader.java:424) 
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) 
 at java.lang.ClassLoader.loadClass(ClassLoader.java:357) 
 ... 5 more 
FATAL ERROR in native method: processing of -javaagent failed 
아직 구체 적 인 이 유 는 모 르 겠 지만...그래서 그냥 클 라 스 로 실행 하면 돼 요.
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기