ClassLoader 테스트 사용자 정의

6318 단어
사용자 정의 ClassLoader는 ClassLoader 추상 클래스를 직접 상속하고 덮어쓰기
protected Class> findClass(String name) throws ClassNotFoundException

사용자 정의 로드 클래스를 실현하는 방법입니다.#ClassLoader 추상 클래스에서는 Class 인스턴스화 방법을 제공합니다.
protected final Class> defineClass(byte[] b, int off, int len)

이 방법의 목적은class 바이트를class instance로 유전시키는 것이다
/**
* Converts an array of bytes into an instance of class Class.
* Before the Class can be used it must be resolved.
*
* 

This method assigns a default {@link java.security.ProtectionDomain * ProtectionDomain} to the newly defined class. The * ProtectionDomain is effectively granted the same set of * permissions returned when {@link * java.security.Policy#getPermissions(java.security.CodeSource) * Policy.getPolicy().getPermissions(new CodeSource(null, null))} * is invoked. The default domain is created on the first invocation of * {@link #defineClass(String, byte[], int, int) defineClass}, * and re-used on subsequent invocations. * *

To assign a specific ProtectionDomain to the class, use * the {@link #defineClass(String, byte[], int, int, * java.security.ProtectionDomain) defineClass} method that takes a * ProtectionDomain as one of its arguments.

* * @param name * The expected binary name of the class, or * null if not known * * @param b * The bytes that make up the class data. The bytes in positions * off through off+len-1 should have the format * of a valid class file as defined by * The Java™ Virtual Machine Specification. * * @param off * The start offset in b of the class data * * @param len * The length of the class data * * @return The Class object that was created from the specified * class data. * * @throws ClassFormatError * If the data did not contain a valid class * * @throws IndexOutOfBoundsException * If either off or len is negative, or if * off+len is greater than b.length. * * @throws SecurityException * If an attempt is made to add this class to a package that * contains classes that were signed by a different set of * certificates than this class (which is unsigned), or if * name begins with "java.". * * @see #loadClass(String, boolean) * @see #resolveClass(Class) * @see java.security.CodeSource * @see java.security.SecureClassLoader * * @since 1.1 */ protected final Class> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError { return defineClass(name, b, off, len, null); }

이것은 로컬 파일 시스템에서 파일을 통해 읽는 방법*입니다.class 파일, 가져온 모든 class 파일의 바이트를 #defineClass 방법에 전달하는 실례화입니다.그 후에 우리는 이 유형의 대상을 사용할 수 있다.
public class MyClassLoader extends ClassLoader {

    private String dir ;

    public MyClassLoader(String dir) {
        //
        this.dir = dir ;
    }

    @Override
    public Class> findClass(String name) throws ClassNotFoundException {
        //

        if (StringUtils.isBlank(name))
            throw new ClassNotFoundException() ;

        String path = this.getPath(name) ;

        byte[] ret = this.getClassData(path) ;
        if (ret == null)
            throw new ClassNotFoundException("  ".concat(path).concat("  .")) ;

        return defineClass(name, ret,0, ret.length) ;
    }

    private byte[] getClassData(String path) {
        System.out.println("Path: - ".concat(path));
        try {
            InputStream inputStream = new FileInputStream(new File(path)) ;
            ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
            byte[] buffer = new byte[1024] ;
            while (inputStream.read(buffer) != -1) {
//                baos.write(buffer);
                baos.write(buffer, 0, buffer.length);
            }

            return baos.toByteArray() ;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null ;
    }

    private String getPath(String className) {

        return this.dir.concat(className.replace(".", File.separator)).concat(".class") ;
    }
}


사용자 정의 클래스 로더를 사용하여 로드할 클래스를 원하는 대로 지정합니다.
public class ABean {

    public ABean() {
        System.out.println("   ABean.");
    }

    @Override
    public String toString() {
        return "hello, myClassLoader...." ;
    }
}

테스트 클래스:
public static void main(String[] args) {
        //JVM-classLoader test
        String dir = "/test/target/classess/test/jvm/",
        clsName = "test.jvm.ABean" ;

        MyClassLoader myClassLoader = new MyClassLoader(dir) ;
        try {
            Class cls = myClassLoader.loadClass(clsName) ;
            System.out.println(cls.newInstance().toString()) ;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

//출력
   ABean.
hello, myClassLoader....

주의해야 할 것은
protected final Class> defineClass(String name, byte[] b, int off, int len)

이 방법의 첫 번째 매개 변수는 클래스 전체 이름 [Full-className]을 가리킨다. 그렇지 않으면 이상이 있을 수 있다:java.lang. NoClass Def Found Error 에서 메소드 문서를 작성한 이유는 다음과 같습니다.
* @throws  NoClassDefFoundError
*          If name is not equal to the binary
*          name of the class specified by b

class 파일을 읽은 byteStream의 이름은test/jvm/ABean/class이지만 #defineClass 방법에 전달되는 이름은ABean입니다.
위 코드 테스트 환경은
Linux arch 4.14.10-1-ARCH x86_64 GNU/Linux

트리거 클래스 로드에는 다음 세 가지 방법이 있습니다.
  • 명령줄 부팅 시 JVM 초기화로 로드
  • Class를 통과합니다.forName () 메소드 동적 로드
  • ClassLoader를 통해loadClass() 메소드 동적 로드
  • 클래스 로더에서 클래스를 JVM에 로드하려면 다음 절차를 따르십시오.
     -   :     Class  ;
     -   :           JRE ;           :
          -   :    Class        ;
          -   :             ;
          -   :           ;
     -    :       ,            

    좋은 웹페이지 즐겨찾기