2011-08-28 2 views
1

글래시 피 웹 응용 프로그램에서 동적 클래스로드를 구현하기로 결정했습니다.이 방법은 시도해 보는 방법으로 웹 응용 프로그램에서로드하여 실행할 수있는 작은 플러그인을 지원합니다. 실행 시간. 동적으로로드 된 플러그인 웹을 응용 프로그램에서 인식하도록 만드는 방법

public class PluginManager { 

    private static final String dropBoxDir = "file:///path/to/dropbox/"; 
    private static final URLClassLoader dropBoxClassLoader; 
    static { 
     try { 
     URL dropBoxURL = new URL(dropBoxDir); 
     dropBoxClassLoader = URLClassLoader.newInstance(new URL[]{dropBoxURL}); 
     } 
     catch (MalformedURLException mue) { 
     throw new RuntimeException("MalformedURLException thrown during PluginManager initialization - the hardcoded URL " + dropBoxDir + " must be invalid.", mue); 
     } 
    } 

    //this method is called by a web service 
    public static void runPluginFromDropBox(String fullClassName) { 
     try { 
     //load the plugin class 
     Class<?> pluginClass = dropBoxClassLoader.loadClass(fullClassName); 
     //instantiate it 
     Runnable plugin = (Runnable)pluginClass.newInstance(); 
     //call its run() method 
     plugin.run(); 
     } 
     catch (ClassNotFoundException cnfe) { 
     throw new RuntimeException("The class file for " + fullClassName + " could not be located at the designated directory (" + dropBoxDir + "). Check that the specified class name is correct, and that its file is in the right location.", cnfe); 
     } 
     catch (InstantiationException ie) { 
     throw new RuntimeException("InstantiationException thrown when attempting to instantiate the plugin class " + fullClassName + " - make sure it is an instantiable class with a no-arg constructor.", ie); 
     } 
     catch (IllegalAccessException iae) { 
     throw new RuntimeException("IllegalAccessException thrown when attempting to instantiate the plugin class " + fullClassName + " - make sure the class and its no-arg constructor have public access.", iae); 
     } 
     catch (ClassCastException cce) { 
     throw new RuntimeException("Plugin instance could not be cast to Runnable - plugin classes must implement this interface.", cce); 
     } 
    } 
} 

그런 다음 별도의 프로젝트에, 내가 테스트 플러그인 생성 :

나는 다음과 같은 클래스를 추가

public class TestPlugin implements Runnable { 
    @Override 
    public void run() { 
     System.out.println("plugin code executed"); 
    } 
} 

내가 웹 응용 프로그램을 배포을, 다음 .class 파일로 TestPlugin을 컴파일 그것을 지정된 폴더에 놓습니다. 나는 runPluginFromDropBox()에 클래스 이름으로 도달하고 예상되는 출력을 얻은 웹 서비스를 호출했다.

이 모든 것이 개념의 증거로 사용되었지만 내 웹 응용 프로그램의 클래스를 인식 할 수 없다면 내 플러그인은 실제로 쓸모가 없습니다. 그 후 .war은 독립 실행 형 응용 프로그램으로 만 사용되며 다른 라이브러리의 클래스 경로에는 포함되지 않으므로이 작은 사이드 프로젝트에 적합하지 않습니다.

나는이 토론을 보았다 : Extending Java Web Applications with plugins 그리고 거대한 이유가없는 디자인 도전의 늪에 빠져들고 돌아서 야한다는 느낌을 받는다. 그러나 그 포스트는 일종의 톰캣과 관련이 있기 때문에 정교한 제 3 자 프레임 워크 없이는이 접근법에 대한 직접적인 방법이 있는지 묻습니다.

답변

2

war 파일의 클래스는 특정 클래스 로더에 의해로드되어 같은 서버에 배포 된 다른 웹 응용 프로그램과의 전쟁을 격리하고 전쟁 배포를 취소 할 수 있습니다.

webapp 클래스를 인식하려면 플러그인 클래스 로더가 webapp 클래스 로더를 부모로 사용해야합니다. 추가 클래스 로더를 사용하여 발생할 수있는 모든 문제점을 인식하지 못하고 있지만 컨테이너에서 웹 응용 프로그램의 배포를 취소하고 다시 배포 할 때 메모리 누수 및 기타 불쾌한 문제 (정적 값이 메모리에 유지되는 등)가있을 수 있습니다. 컨테이너 간에도 차이가있을 수 있습니다.

+0

"plugin classloader"라고 말하면 플러그인을로드하는 데 사용하는'URLClassLoader'를 의미합니까? 그 코드는 웹 응용 프로그램에 있지만. 어떻게 든 플러그인이 클래스 패스에 전쟁을 가져가는 것이 얼마나 힘든지 궁금합니다. 그래서 예를 들어 웹 애플리케이션에'Foo' 클래스가 있다면 플러그인은 mywebapp.Foo;를 가져 와서'run()'메소드에서'Foo'와 상호 작용할 수 있습니다 - 아니면 순진하게 벗어나나요? –

+0

예, 저는 플러그인 클래스를로드하는 데 사용 된 클래스 로더에 대해 이야기하고 있습니다. 그리고 내 대답은이 클래스 로더는 전쟁의 클래스 로더가 부모 클래스 로더 여야한다는 것입니다. URLClassLoader의 생성자를 살펴보십시오. 부모 ClassLoader를 인수로 취하는 클래스가 있습니다. 가져 오기는 컴파일시에만 사용됩니다. 컴파일 할 때 웹 클래스에 접근 할 수 있도록 적절한 클래스 경로를 설정하기 만하면됩니다. 런타임에는 전쟁의 클래스 로더가 부모 클래스 로더로 필요합니다. –

+0

좋아요, 부모 클래스 로더에 대해 당신이 말하는 것을 이해합니다. 그러나 나는 이것이 이미 사실이라고 생각한다 - 나는 'newInstance()'에 대한 호출이 부모 클래스 인'ClassLoader'를 디폴트로 사용하고 있다고 잘못 생각하지 않는다면, 이것은 웹 어플리케이션이어야한다. 그래서 내가 뭔가를 놓치지 않는 한 그것이 왜 관련이 있는지 잘 모르겠습니다. 제 질문은 플러그인 라이브러리의 웹 애플리케이션 클래스에 대한 컴파일 타임 인식에 달려 있다고 생각합니다. 나는 여기서 간단한 것을 놓치고 있는가 - 나는 단지 전쟁의 플러그를 클래스 패스에 놓을 수 있을까? –