2010-03-18 2 views
4

웹 애플리케이션을 개발 중입니다.로드 클래스가 웹 애플리케이션에서 클래스 경로에 동적으로 있지 않습니다. - 사용자 정의 클래스 로더를 사용하지 않습니다.

  1. 웹 응용 프로그램은 자바 클래스를 즉석에서 생성합니다. 예를 들어, 클래스를 생성합니다 com.people.Customer.java
  2. 내 코드에서 com.people.Customer.class를 가져 와서 일부 디렉토리에 저장하기 위해 동적으로 컴파일합니다. repository/com/people/Customer.class은 내 응용 프로그램 server.My 응용 프로그램 서버의 클래스 경로에 없습니다. WebSphere Application Server/Apache Tomcat 등 사용)은 WEB-INF/classes 디렉토리에서 클래스를 선택합니다. Classloader는 이것을 사용하여 클래스를로드합니다.
  3. 컴파일 한 후이 클래스를로드해야 생성 후에 다른 클래스에서 액세스 할 수 있습니다.
  4. Thread.currentThread().getContextClassLoader().loadClass(com.people.Customer)을 사용하면 분명히 Classloader는 클래스 경로에 있지 않으므로 클래스를로드 할 수 없습니다 (WEB-INF/classes에는 없음). 비슷한 이유로 인해 getResource(..) 또는 getResourceAsStream(..)도 작동하지 않습니다. 어쩌면 스트림 (또는 할 것입니다 다른 방법) 다음로드로 클래스 Customer.class 읽기

    :

내가 할 수있는 방법이 필요하다. 다음은 제약 조건입니다.

  1. WEB-INF/classes 폴더에 저장소 폴더를 추가 할 수 없습니다.
  2. 새 사용자 정의 클래스 로더를 만들 수 없습니다. 새 ClassLoader를 만들고이 클래스를로드하면 상위 ClassLoader에서 액세스 할 수 없습니다.

이 방법이 있습니까?

더 나쁜 경우 웹 응용 프로그램의 사용자 정의 클래스 로더를 기본 클래스 로더로 대체하는 방법이 있습니까? 동일한 웹 응용 프로그램의 전체 수명주기 동안 동일한 클래스 로더를 사용하여 응용 프로그램을로드해야합니다.

어떤 솔루션 :

+1

왜 WEB-INF/classes 폴더에 추가 할 수 없습니까? 이것이 진정한 해결책입니다. 어떤 상황에서도 "할 수 없다", "하지 않을 것인가", 또는 "하지 않을 것인가"인가? – duffymo

+0

@duffymo : webapp이 확장 모드로 배포되고 webapp에 파일 시스템에 대한 쓰기 권한이 있다고 가정합니다. 프로덕션 환경에서 항상 그런 것은 아닙니다. WEB-INF/classes에 파일을 쓰는 것은 좋은 해결책이 아닙니다. – mhaller

+1

아니, 그 어떤 것도 가정하지 않습니다. 여러분의 투시력이 떨어졌습니다. mhaller. 나는 필요한 모든 .class 파일을 포함하고 재배포하기 위해 WAR을 다시 포장해야한다고 주장한다. 고객의 입장에서 명백한 것을 만들어야하는 유스 케이스를보고 싶습니다. 인스턴스? 예. 수업? 아니, 나는 그것을 사지 않을거야. – duffymo

답변

1

짧은 답변 감사합니다 : 없음

사용자 정의 클래스 로더없이를 동적으로 클래스를로드 할 수 없습니다.

그러나 WebApp ClassLoader가로드 한 다른 오브젝트가 새로로드 된 클래스를 사용할 수 없으므로 사용자 정의 ClassLoader를 사용할 수 없다고 가정하면 올바르지 않습니다. 공통 인터페이스 또는 메타 설명 (Bean 속성에 액세스하기위한 Beans Introspector)과 같이 새로 생성 된 클래스를 사용하는 일반적인 방법이 필요합니다.

하지만 Hibernate와 같은 타사 라이브러리를 사용하고 있으며 런타임에 지속성을 유지할 엔티티를 동적으로로드하는 경우 어려움을 겪을 수 있지만 곧 발생할 수 있습니다.

1

물론 가능합니다. 웹 클래스 로더를 가져 와서 리플렉션을 사용하여 defineClass() 메서드를 호출하십시오 (보호되어 있으므로 메서드에서 setAccessible (true)를 호출해야합니다.) defineClass()는 바이트 배열을 사용하므로 사용자가 클래스 이름은 고유해야하며 클래스를 한 번만로드하면 클래스로드 문제가 복잡해집니다.에서 다음

public class CustomClassLoader extends ClassLoader { 

    final String basePath = "/your/base/path/to/directory/named/repository/"; 

    @Override 
    protected Class<?> findClass(final String name) throws ClassNotFoundException { 
     String fullName = name.replace('.', '/'); 
     fullName += ".class"; 

     String path = basePath + fullName ; 
     try { 
      FileInputStream fis = new FileInputStream(path); 
      byte[] data = new byte[fis.available()]; 
      fis.read(data); 
      Class<?> res = defineClass(name, data, 0, data.length); 
      fis.close(); 

      return res; 
     } catch(Exception e) { 
      return super.findClass(name); 
     } 
    } 
} 

, 당신이있을거야 부하 클래스를 다시 정의하는 방법 findClass(String name)

예는에

+0

당신은 솔루션이 좋지만 웹 클래스 로더는 환경마다 다르므로 내 코드를 비 protable로 만들 것입니다. –

+0

아니요. defineClass()는 모든 클래스 로더가 공유하는 ClassLoader 메소드입니다. –

2

는이 작업을 수행하는 사용자 정의 클래스 로더를해야하고,이 클래스 로더에 당신이 필요 맞춤 위치. 예를 들어 :

Class<?> clazz = Class.forName("my.pretty.Clazz", true, new CustomClassLoader()); 
Object obj = clazz.newInstance(); 

는 이렇게, 당신은 my.pretty.Clazz라는 이름의 클래스가에서 사용자 정의 클래스를로드하는 방법를 알고있는 사용자 정의 클래스 로더에 의해로드해야 JVM을 말한다. 전체 클래스 이름 (예 : my.pretty.Clazz)을 파일 이름 (이 경우 /your/base/path/to/directory/named/repository/my/pretty/Clazz.class)으로 확인한 다음 가져온 리소스를 바이트 배열로로드하고 마지막으로이 배열을 Class 인스턴스로 변환합니다.

이 예제는 매우 간단하며 사용자 정의 클래스를로드하는 방법에 대한 일반적인 기술을 보여줍니다. 클래스 로딩에 대한 몇 가지 기사를 읽어 보시기 바랍니다 (예 : this one).