자바 사용자 정의 클래스 로 더 기반 열 배치 프로 세 스 분석

열 배치:
열 배 치 는 응용 프로그램 을 다시 시작 하지 않 은 상태 에서 클래스 의 정의 인 바이트 코드 파일 이 수정 되면 이 Class 가 만 든 대상 을 교체 할 수 있 습 니 다.일반적으로 클래스 의 로 딩 은 시스템 이 자체 적 으로 가지 고 있 는 클래스 로 딩 기 에 의 해 이 루어 지 며,같은 전체 이름 의 자바 류 에 대해 서 는 한 번 만 불 러 올 수 있 으 며,마 운 트 해제 할 수 없습니다.사용자 정의 ClassLoader 를 사용 하여 시스템 의 로 더 를 교체 할 수 있 습 니 다.새로운 ClassLoader 를 만 들 고 클 라 스 를 불 러 올 수 있 습 니 다.클 라 스 대상 은 새로운 것 입 니 다.(같은 종류의 로 더 가 아니 기 때 문 입 니 다)이 클 라 스 대상 으로 인 스 턴 스 를 만 들 고 동적 으로 새로운 것 을 실현 합 니 다.예 를 들 어 JSP 파일 을 수정 하면 효력 이 발생 합 니 다.사용자 정의 ClassLoader 를 이용 하여 이 루어 집 니 다.
데 몬 스 레 드 를 만 들 고 클 라 스 파일 이 수정 되 었 는 지 계속 확인 하 며 파일 의 마지막 수정 시간 을 판단 해 야 합 니 다.
프레젠테이션:
원래 프로그램:

수정 후 다시 컴 파일:

코드:

package Dynamic;
 
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
 
public class ClassLoadStudy {
  public static void main(String[] args) throws Exception {
    HotDeploy hot = new HotDeploy("Dynamic.Task");
    hot.monitor();
    while (true) {
      TimeUnit.SECONDS.sleep(2);
      hot.getTask().run();
    }
  }
}
 
//    
 
class HotDeploy {
  private static volatile Runnable instance;
  private final String FILE_NAME;
  private final String CLASS_NAME;
 
  public HotDeploy(String name) {
    CLASS_NAME = name; //        
    name = name.replaceAll("\\.", "/") + ".class";
    FILE_NAME = (getClass().getResource("/") + name).substring(6); //   class        ,substring(6)     file:/
  }
 
  //       
  public Runnable getTask() {
    if (instance == null) { //      ,  ,    
      synchronized (HotDeploy.class) {
        if (instance == null) {
          try {
            instance = createTask();
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      }
    }
    return instance;
  }
 
  //       ,     class   
  private Runnable createTask() {
    try {
      Class clazz = MyClassLoader.getLoader().loadClass(CLASS_NAME);
      if (clazz != null)
        return (Runnable)clazz.newInstance();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }
 
 
  //    ,  class        ,     ,     
  public void monitor() throws IOException {
    Thread t = new Thread(()->{
      try {
        long lastModified = Files.getLastModifiedTime(Path.of(FILE_NAME)).toMillis();
        while(true) {
          Thread.sleep(500);
          long now = Files.getLastModifiedTime(Path.of(FILE_NAME)).toMillis();
          if(now != lastModified) { //   class       
            lastModified = now;
            instance = createTask(); //     
          }
        }
      } catch (InterruptedException | IOException e) {
        e.printStackTrace();
      }
    });
    t.setDaemon(true); //     
    t.start();
  }
}
 
//         
class MyClassLoader extends ClassLoader {
  @Override
  public Class<?> findClass(String name) throws ClassNotFoundException {
    try {
      String fileName = "/" + name.replaceAll("\\.", "/") + ".class";
      InputStream is = getClass().getResourceAsStream(fileName);
      byte[] b = is.readAllBytes();
      return defineClass(name, b, 0, b.length);
    } catch (IOException e) {
      throw new ClassNotFoundException(name);
    }
  }
  public static MyClassLoader getLoader() {
    return new MyClassLoader();
  }
}
만난 구덩이:
처음에는 클래스 로 더 를 사용자 정의 할 때 loadClass(String name)방법 을 다시 썼 으 나 오류 가 계속 발생 했 습 니 다.나중에 알 게 되 었 습 니 다.Task 류 가 자바.lang.Runnable 인 터 페 이 스 를 실현 하고 loadClass 를 다시 쓰 는 방법 은 부모 위임 체 제 를 파괴 하여 사용자 정의 클래스 로 더 를 자바.lang.Runnable 로 불 러 왔 으 나 자바 보안 체제 에 의 해 금지 되 어 오류 가 발생 했 습 니 다.defineClass 는 preDefineClass 를 호출 합 니 다.preDefineClass 는 패키지 이름 을 검사 합 니 다.자바 로 시작 하면 이상 을 던 집 니 다.사용자 정의 클래스 로 더 를 불 러 와 자바 자체 라 이브 러 리 를 불 러 오 는 것 이 혼 란 스 럽 기 때 문 입 니 다.
그래서 findClass 방법 을 다시 썼 지만 안 됩 니 다.findClass 방법 은 항상 실행 되 지 않 습 니 다.컴 파일 된 클래스 는 classpath 에 있 기 때 문 입 니 다.사용자 정의 ClassLoader 의 부모 로 더 는 AppClassLoader 입 니 다.부모 위임 체제 로 인해 클래스 는 Application ClassLoader 에 의 해 불 러 옵 니 다.따라서 사용자 정의 findClass 방법 은 실행 되 지 않 습 니 다.해결 방법 은 구조 기 ClassLoader(ClassLoader parent)에 null 을 전송 하거나 getSystem ClassLoader().getParent()를 전송 하 는 것 입 니 다.
그리고 경로 문제:
4.567917.path 가/로 시작 하지 않 을 때 기본 값 은 이러한 가방 에서 자원 을 가 져 옵 니 다.path 가/로 시작 할 때 ClassPath 루트 에서 가 져 옵 니 다.
  • URL getClass.getResource(String path)
  • InputStream getClass().getResourceAsStream(String path)
  • getResource(")는 현재 클래스 가 있 는 가방 의 경 로 를 되 돌려 줍 니 다
  • getResource("/")는 현재 classpath 를 경로 에 따라 되 돌려 줍 니 다
  • path 는/로 시작 할 수 없습니다.path 는 classpath 루트 에서 계산 합 니 다.classloader 는 사용자 정의 클래스 가 아니 기 때문에 상대 적 인 경로 의 설정 파일 을 가 져 올 수 없 기 때문에 기본 값 은 어느 classpath 경로 에서 읽 습 니까?자 연 스 럽 게/로 시작 할 필요 가 없습니다.
  • URL Class.getClassLoader().getResource(String path)
  • InputStream Class.getClassLoader().getResourceAsStream(String path)
  • 이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기