지정된 class 파일을 로드하는 커스텀 ClassLoader 구현

자바에서 특정 경로에 있는 컴파일된 .class 파일을 동적으로 로드해야 하는 경우, 기본 제공되는 클래스 로더 대신 사용자 정의 ClassLoader를 작성할 수 있다. 이를 위해 ClassLoader 클래스를 상속하고 findClass 메서드를 오버라이드하면 된다.

먼저, 별도의 패키지에 존재하는 테스트용 클래스를 하나 준비한다. 아래는 cn.lijie 패키지 내에 위치한 BugNew 클래스 예시이다.

package cn.lijie;

public class BugNew {
    public void display() {
        System.out.println("Custom class loaded successfully!");
    }
}

이 클래스는 컴파일 후 다음과 같은 경로에 저장된다:
/D:/infosec/netauth/accountsync/BugNew.class
패키지 구조에 맞춰 디렉터리 계층을 유지해야 하며, 이 경우 cn/lijie/BugNew.class 형태로 배치되어야 한다.

다음은 사용자 정의 클래스 로더 구현체이다. 지정된 URI 경로에서 바이트 데이터를 읽어와 defineClass를 통해 클래스 객체를 생성한다.

package com.infosec.manager.controller.login;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class CustomClassLoader extends ClassLoader {

    private String classPath = "file:///D:/infosec/netauth/accountsync/BugNew.class";

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            URI uri = new URI(classPath);
            Path path = Paths.get(uri);
            byte[] classBytes = Files.readAllBytes(path);

            // 클래스 이름은 전체 경로 기준으로 정확히 일치해야 함
            return defineClass(name, classBytes, 0, classBytes.length);
        } catch (IOException | URISyntaxException e) {
            throw new ClassNotFoundException("Failed to load class from custom path", e);
        }
    }
}

이제 이 커스텀 로더를 사용해 외부 클래스를 로드하고 메서드를 실행하는 테스트 코드를 작성한다.

package com.infosec.manager.controller.login;

import java.lang.reflect.Method;

public class LoaderTest {

    public static void main(String[] args) {
        CustomClassLoader loader = new CustomClassLoader();
        try {
            // 수동으로 클래스 이름 전달
            Class<?> loadedClass = loader.findClass("cn.lijie.BugNew");
            Object instance = loadedClass.newInstance();

            Method method = loadedClass.getMethod("display");
            method.invoke(instance);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

실행 결과로 "Custom class loaded successfully!"가 출력되면, 외부의 .class 파일이 성공적으로 로드되고 인스턴스화되었음을 의미한다.

추가적으로, 런타임 시 객체가 특정 인터페이스를 구현했는지 확인해야 할 경우 다음처럼 처리할 수 있다.

private boolean hasTargetInterface(Object target) {
    if (target instanceof SynchAccountApi || target instanceof SyncUsersFromAppInterface) {
        return true;
    }

    Class<?>[] interfaces = target.getClass().getInterfaces();
    return Arrays.stream(interfaces)
                 .anyMatch(clazz -> clazz.getName().contains("SynchAccountApi"));
}

이 방식은 스프링의 ClassUtils.getAllInterfaces()를 직접 사용하지 않고도 인터페이스 구현 여부를 유연하게 검사할 수 있도록 도와준다.

태그: java ClassLoader reflection CustomClassLoader Runtime Loading

7월 17일 03:42에 게시됨