1

런타임에 클래스 파일을 생성 중입니다.바람둥이의 클래스 파일 재로드

기존 클래스 파일을 클래스 로더의 업데이트 된 파일로 대체하려고합니다.

이는 서버 재시작 및 재배포를 피하는 핫 스왑 (예 : JRebel)과 유사합니다.

컨텍스트 재로드를 위해 tomcat에 대한 context.xml 접근 방식을 찾았습니다. 그러나 프로덕션 환경의 경우에는별로 유용하지 않습니다.

런타임시 ClassLoader로 클래스를 등록 할 수 있습니까? 런타임에 클래스를 다시로드 할 수있는 대안이 있는지 제안하십시오.


현재 classLoader를 검색하는 데 다음 코드를 사용하고 있습니다.

ClassLoader classLoader = LoggingAspect.class.getClassLoader(); 

다음은로드 클래스 메소드의 구현 방법입니다.

public class AspectClassLoader extends ClassLoader{ 

@Override 
public synchronized Class<?> loadClass(String name) throws ClassNotFoundException 
{ 
    String customLoadClass = "com.log.LoggingAspect"; 
    try 
    { 
     if(!customLoadClass.equals(name)) 
     { 
      return super.loadClass(name); 
     } 
     else 
     { 
      URL classLoadUrl = new URL(this.reloadClassUrl); 
      URLConnection connection = classLoadUrl.openConnection(); 
      InputStream input = connection.getInputStream(); 
      ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 
      int data = input.read(); 

      while(data != -1){ 
       buffer.write(data); 
       data = input.read(); 
      } 

      input.close(); 

      byte[] classData = buffer.toByteArray(); 
      return defineClass(name, classData, 0, classData.length); 
     } 
    } 
    catch(Exception e) 
    { 
     e.printStackTrace(); 
    } 
    return null; 
} 

클래스를 다시로드하려면 다음 코드를 사용하고 있습니다. 클래스 로더의

AspectClassLoader urlClsLoader = new AspectClassLoader(classLoader); 
Class aspect = urlClsLoader.reloadClass("com.log.LoggingAspect", true, new String("file:"+className)); 

내 재 장전 방법은 내가 LoggingAspect의 새 인스턴스를 만들 경우 여전히 나에게 이전 인스턴스를 제공 다시로드 한 후

public synchronized Class<?> reloadClass(String name, boolean resolve, String reloadClassUrl) throws ClassNotFoundException 
{ 
    this.reloadClassUrl = reloadClassUrl; 
    return this.loadClass(name, resolve); 
} 

입니다. 제발 제안 해주세요.

Class aspect = urlClsLoader.reloadClass("com.log.LoggingAspect", true, new String("file:"+className)); 
     com.log.aspect.Aspect aspectObj = (com.log.aspect.Aspect)aspect.newInstance(); 

여전히 오래된 인스턴스가 나타납니다.

왜 클래스 로더가 수정 된 클래스를로드하지 않는지 제안하십시오.

답변

2

이것은 가능하지만 복잡합니다. 현재 ClassLoader을 부모로 사용하여 새로 URLClassLoader을 작성하면됩니다. 새로운 URLClassLoader

다음에 (패키지 폴더 제외) 클래스와 폴더의 URL을 추가, 당신은 그렇지 않으면 (parent.loadClass()를 호출하기 전에 새로운 클래스를 반환하는 loadClass()를 패치해야합니다, 기존의 클래스가 사용되며 업데이트 하나는 무시 될 것이다).

사용할 때 복잡해진다. 새로운 클래스. 이를 위해서는 새 클래스 로더를 사용하여 클래스를 만들고 모든 사용자가이 유형의 인스턴스를 사용해야합니다.

클래스가 WAR에없는 경우 더 안전하고 디버깅하기가 쉽습니다. 형식을 사용하는 대신 URLClassLoader 클래스를로드하고 해당 인스턴스를 만듭니다. 그래서이 클래스를 사용하여 코드는 다음과 같이 작동합니다

IService service = createService(); 

IService가 생성 된 클래스가 지원하는 메소드를 정의하는 인터페이스입니다. 그렇게하면 구현이 실제로 필요하지 않고 메서드를 사용하는 코드를 작성할 수 있습니다.