바이트코드 조작 툴 활용 예
프로그램 분석
바이트코드를 읽으면서 코드에서 버그를 찾을 수 있습니다. 또한, 코드의 복잡도를 계산할 수 있습니다.
- 소스코드 없이 바이트코드만 있어도 이러한 것들이 분석 가능합니다.
클래스 파일 생성
원래 소스코드 대신에 실행할 프록시를 만들 수 있습니다.
- 스프링 AOP, Hibernate의 Lazy Loading, Mock 프레임워크
또한, 특정한 API 호출을 제한(방어)할 수 있습니다. 그리고 스칼라와 같은 JVM 언어들을 컴파일을 할때 바이트코드를 생성해냄으로써 JVM 위에서 돌아갈 수 있게끔 해줍니다.
그밖에
자바 소스 코드 건드리지 않고 코드 변경이 필요한 여러 경우에 사용할 수 있습니다.
- 프로파일러
- 프로파일러란 실행중인 애플리케이션이 메모리를 얼만큼 쓰고있는지, 쓰레드가 몇 개인지, 어떤 쓰레드들이 활성화되어 있고 어떤게 가장 오래 일하고 있는지 등의 각종 성능 분석 툴입니다.
- 이러한 툴들이 javaagent로 바이트코드를 조작해서 자기들이 원하는 정보를 추출하거나 코드를 변경해서 특정 값을 구할 때 사용합니다.
- ex) Naver의 Pinpoint
- 최적화
- 바이트코드를 조작하여 불필요한 코드를 제거하거나 중복 코드를 제거하는 등의 최적화를 할 수 있습니다.
- 로깅
- …
스프링이 컴포넌트 스캔을 하는 방법 (asm)
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
...
}
컴포넌트 스캔으로 빈으로 등록할 후보 클래스 정보를 찾는데 사용합니다. 이때 사용하는 클래스가 ClassPathScanningCandidateComponentProvider
입니다. 내부적으로 asm을 사용합니다.
MetadataReader metadataReader = this.getMetadataReaderFactory().getMetadataReader(type);
- ClassPathScanningCandidateComponentProvider 코드 일부
- type에서 메타 데이터를 읽어오는데 이때 사용하는게 SimpleMetadataReader 입니다.
SimpleMetadataReader에서 ClassReader와 Visitor 구현체를 이용해서 클래스 또는 메서드에 붙어있는 애노테이션 정보들을 추출해오는데 사용합니다. 즉, 프로그램을 분석하는 것입니다.
package org.springframework.asm;
...
public class ClassReader {
...
}
- ClassReader가 asm에서 온 것입니다.
즉, 이렇게 빈으로 등록할 대상을 찾는데 사용하고 있습니다.
참고
바이트조작 라이브러리로는 ASM, Javassit, ByteBuddy, CGlib 등이 있습니다.
- ASM은 고전, ByteBuddy는 비교적 최근 라이브러리입니다.
- 스프링은 ASM을 사용중입니다.
- Hibernate는 javassist에서 ByteBuddy로 갈아타고 있습니다.
- Mockito는 CGLib에서 ByteBuddy로 갈아탔습니다.