Java Language
자바 플러그인 시스템 구현
수색…
비고
IDE 및 / 또는 빌드 시스템을 사용하는 경우 이러한 종류의 프로젝트를 설정하는 것이 훨씬 쉽습니다. 기본 응용 프로그램 모듈을 작성한 다음 API 모듈을 작성한 다음 플러그인 모듈을 작성하여 API 모듈 또는 둘 다에 종속되게하십시오. 다음으로, 프로젝트 아티팩트가 놓일 위치를 설정합니다. 우리의 경우 컴파일 된 플러그인 jar를 'plugins'디렉토리로 곧바로 보낼 수 있으므로 수동으로 이동하지 않아도됩니다.
URLClassLoader 사용
Java 응용 프로그램 용 플러그인 시스템을 구현하는 데는 여러 가지 방법이 있습니다. 가장 간단한 방법 중 하나는 URLClassLoader 를 사용하는 것입니다. 다음 예제는 약간의 JavaFX 코드를 포함합니다.
주 응용 프로그램 모듈이 있다고 가정합니다. 이 모듈은 'plugins'폴더에서 Jars 형식으로 플러그인을로드하기로되어 있습니다. 초기 코드 :
package main;
public class MainApplication extends Application
{
@Override
public void start(Stage primaryStage) throws Exception
{
File pluginDirectory=new File("plugins"); //arbitrary directory
if(!pluginDirectory.exists())pluginDirectory.mkdir();
VBox loadedPlugins=new VBox(6); //a container to show the visual info later
Rectangle2D screenbounds=Screen.getPrimary().getVisualBounds();
Scene scene=new Scene(loadedPlugins,screenbounds.getWidth()/2,screenbounds.getHeight()/2);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] a)
{
launch(a);
}
}
그런 다음 플러그인을 나타내는 인터페이스를 만듭니다.
package main;
public interface Plugin
{
default void initialize()
{
System.out.println("Initialized "+this.getClass().getName());
}
default String name(){return getClass().getSimpleName();}
}
이 인터페이스를 구현하는 클래스를로드하려고하므로 먼저 '.jar'확장자가있는 파일을 필터링해야합니다.
File[] files=pluginDirectory.listFiles((dir, name) -> name.endsWith(".jar"));
파일이있는 경우 URL 및 클래스 이름의 컬렉션을 만들어야합니다.
if(files!=null && files.length>0)
{
ArrayList<String> classes=new ArrayList<>();
ArrayList<URL> urls=new ArrayList<>(files.length);
for(File file:files)
{
JarFile jar=new JarFile(file);
jar.stream().forEach(jarEntry -> {
if(jarEntry.getName().endsWith(".class"))
{
classes.add(jarEntry.getName());
}
});
URL url=file.toURI().toURL();
urls.add(url);
}
}
로드 된 플러그인을 보유 할 MainApplication에 정적 HashSet을 추가해 보겠습니다.
static HashSet<Plugin> plugins=new HashSet<>();
다음으로 URLClassLoader를 인스턴스화하고 클래스 이름을 반복하여 Plugin 인터페이스를 구현하는 클래스를 인스턴스화합니다.
URLClassLoader urlClassLoader=new URLClassLoader(urls.toArray(new URL[urls.size()]));
classes.forEach(className->{
try
{
Class cls=urlClassLoader.loadClass(className.replaceAll("/",".").replace(".class","")); //transforming to binary name
Class[] interfaces=cls.getInterfaces();
for(Class intface:interfaces)
{
if(intface.equals(Plugin.class)) //checking presence of Plugin interface
{
Plugin plugin=(Plugin) cls.newInstance(); //instantiating the Plugin
plugins.add(plugin);
break;
}
}
}
catch (Exception e){e.printStackTrace();}
});
그런 다음 플러그인의 메소드를 호출하여 초기화 할 수 있습니다.
if(!plugins.isEmpty())loadedPlugins.getChildren().add(new Label("Loaded plugins:"));
plugins.forEach(plugin -> {
plugin.initialize();
loadedPlugins.getChildren().add(new Label(plugin.name()));
});
MainApplication 의 최종 코드 :
package main;
public class MainApplication extends Application
{
static HashSet<Plugin> plugins=new HashSet<>();
@Override
public void start(Stage primaryStage) throws Exception
{
File pluginDirectory=new File("plugins");
if(!pluginDirectory.exists())pluginDirectory.mkdir();
File[] files=pluginDirectory.listFiles((dir, name) -> name.endsWith(".jar"));
VBox loadedPlugins=new VBox(6);
loadedPlugins.setAlignment(Pos.CENTER);
if(files!=null && files.length>0)
{
ArrayList<String> classes=new ArrayList<>();
ArrayList<URL> urls=new ArrayList<>(files.length);
for(File file:files)
{
JarFile jar=new JarFile(file);
jar.stream().forEach(jarEntry -> {
if(jarEntry.getName().endsWith(".class"))
{
classes.add(jarEntry.getName());
}
});
URL url=file.toURI().toURL();
urls.add(url);
}
URLClassLoader urlClassLoader=new URLClassLoader(urls.toArray(new URL[urls.size()]));
classes.forEach(className->{
try
{
Class cls=urlClassLoader.loadClass(className.replaceAll("/",".").replace(".class",""));
Class[] interfaces=cls.getInterfaces();
for(Class intface:interfaces)
{
if(intface.equals(Plugin.class))
{
Plugin plugin=(Plugin) cls.newInstance();
plugins.add(plugin);
break;
}
}
}
catch (Exception e){e.printStackTrace();}
});
if(!plugins.isEmpty())loadedPlugins.getChildren().add(new Label("Loaded plugins:"));
plugins.forEach(plugin -> {
plugin.initialize();
loadedPlugins.getChildren().add(new Label(plugin.name()));
});
}
Rectangle2D screenbounds=Screen.getPrimary().getVisualBounds();
Scene scene=new Scene(loadedPlugins,screenbounds.getWidth()/2,screenbounds.getHeight()/2);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] a)
{
launch(a);
}
}
두 개의 플러그인을 만들어 보겠습니다. 분명히, 플러그인의 소스는 별도의 모듈에 있어야합니다.
package plugins;
import main.Plugin;
public class FirstPlugin implements Plugin
{
//this plugin has default behaviour
}
두 번째 플러그인 :
package plugins;
import main.Plugin;
public class AnotherPlugin implements Plugin
{
@Override
public void initialize() //overrided to show user's home directory
{
System.out.println("User home directory: "+System.getProperty("user.home"));
}
}
이러한 플러그인은 표준 Jars에 패키지되어야합니다.이 프로세스는 IDE 또는 다른 도구에 따라 다릅니다.
Jars가 '플러그인'에 직접 삽입되면 MainApplication 은 해당 플러그인을 감지하고 적절한 클래스를 인스턴스화합니다.