2011-10-14 12 views
11

私はバックエンドサービスのデフォルトimplで実行しているWebアプリケーションを持っています。 1つは、インターフェイスを実装し、プラグインフォルダ(アプリケーションのクラスパスにはない)にjarファイルをドロップできるはずです。サーバーが再起動したら、新しいjarをクラスローダーにロードし、依存関係注入に参加させることが考えられます。 @Autowiredを使ってSpring DIを使用しています。新しいプラグインサービスimplには@Primaryアノテーションが付きます。インターフェイスの2つの意味が与えられているので、プライマリをロードする必要があります。春の依存性注入とプラグインの瓶

jarをクラスローダーにロードして、手動でimplを呼び出すことができます。しかし、私はDependency Injectionに参加することができず、デフォルトのimplを置き換えることができませんでした。ここで

は簡単な例です:より良い場所がないために

@Controller 
public class MyController { 
    @Autowired 
    Service service; 
} 

//default.jar 
@Service 
DefaultService implements Service { 
    public void print() { 
     System.out.println("printing DefaultService.print()"); 
    } 
} 

//plugin.jar not in classpath yet 
@Service 
@Primary 
MyNewService implements Service { 
    public void print() { 
     System.out.println("printing MyNewService.print()"); 
    } 
} 

//、私は、私はクラスローダにjarファイルをロードした後でもContextListener

public class PluginContextLoaderListener extends org.springframework.web.context.ContextLoaderListener { 

     @Override 
     protected void customizeContext(ServletContext servletContext, 
             ConfigurableWebApplicationContext wac) { 
       System.out.println("Init Plugin"); 
       PluginManager pluginManager = PluginManagerFactory.createPluginManager("plugins"); 
       pluginManager.init(); 

        //Prints the MyNewService.print() method 
        Service service = (Service) pluginManager.getService("service"); 
        service.print();     
      } 
    } 

    <listener> 
      <listener-class>com.plugin.PluginContextLoaderListener</listener-class> 
    </listener> 

からプラグインのjarファイルをロードDefaultServiceはまだサービスとしてインジェクトされています。どのようにプラグインジャーを春のDIライフサイクルに参加させるのか?

編集: 簡単に言えば、戦争中のプラグインディレクトリにいくつかのプラグインジャーを持つ戦争ファイルがあります。アプリケーションが見ている設定ファイルの値に基づいて、アプリケーションが起動されると、その特定のプラグインjarをロードし、そのアプリケーションを実行したいと思う。そうすれば、私は戦争を誰にでも配布することができ、すべてのパッケージを再パッケージする必要なしに、設定値に基づいて実行するプラグインを選択することができます。これは私が解決しようとしている問題です。

答えて

7

あなたはスプリングApplicationContextを正しく作成する必要があるようです。可能であればクラスパス混在なしと思う。最も重要なことは、Springのコンフィグレーションファイルの場所がのクラスパスであることです。あなたのプラグインの瓶はすべてWEB-INF/libに入れてお読みください。

コアモジュールから始めましょう。 classpath*:META-INF/spring/*-corecontext.xmlにあるファイルからApplicationContextというファイルを作成します。

ここでは、すべてのプラグインの設定ファイルを別の場所に設定します。私。 'myplugin1'の設定位置はclasspath*:META-INF/spring/*-myplugin1context.xmlのようになります。 anotherpluginの設定はclasspath*:META-INF/spring/*-anotherplugincontext.xmlになります。

あなたが見るものはですconvensionです。あなたが好きな場合にも、subdirectiriesを使用することができます。

  • コア:classpath*:META-INF/spring/core/*.xml
  • myplugin1:classpath*:META-INF/spring/myplugin1/*.xml
  • anotherplugin:classpath*:META-INF/spring/anotherplugin/*.xml

大事なことは場所が互いに素しなければならないことです。

残りのすべては、適切な場所をApplicationContextクリエイターに渡すことだけです。 Webアプリケーションの場合は、ContextLoaderListenerを拡張し、customizeContext(ServletContext, ConfigurableWebApplicationContext)メソッドをオーバーライドするのが適切です。

あなたの設定ファイル(その場所はサーブレットのinitパラメータとして渡すことができます)を読むだけです。あなたは、設定場所のリストを構築するために必要以上:あなたは簡単に何で、どのような春ApplicationContextにロードされていないを管理することができます

String locationPrefix = "classpath*:META-INF/spring/"; 
String locationSiffix = "/*.xml"; 

List<String> configLocations = new ArrayList<String>(); 
configLocations.add(locationPrefix + "core" + locationSiffix); 

List<String> pluginsTurnedOn = getPluginsTurnedOnFromConfiguration(); 
for (String pluginName : pluginsTurnedOn) { 
    configLocations.add(locationPrefix + pluginName + locationSiffix); 
} 

applicationContext.setConfigLocations(configLocations.toArray(new String[configLocations.size()])); 

この方法です。

更新:

が、それは私が今説明しようとしてだと私が作ったもう一つの隠された前提があります動作させるために。 ベースパッケージコアモジュールと各プラグインもdisjointである必要があります。それはすなわちです:

  • com.mycompany.myapp.myplugin1
  • com.mycompany.myapp.anotherplugin
  • この方法で、各モジュールが<context:componet-scan />を使用することができます

    • com.mycompany.myapp.core (JavaConfigの同等の機能)を簡単に追加することができます。のクラスパスは、それ自身のクラスだけですです。コアモジュールには、には、すべてのプラグインパッケージのパッケージスキャンが含まれていてはなりません。 プラグインは、クラスパススキャンに独自のパッケージを追加するために、設定ApplicationContextに拡張する必要があります。

    +0

    ありがとうございます。それがうまくいくように見えます。しかし、私は春の注釈を頻繁に使用していますし、プラグインの瓶には春のXMLもありません。私は、Annotation-driven dependency injectionについて上記と同じようにするのがどれほど簡単だろうと思います。 – Langali

    +0

    各プラグインには何らかの設定が必要です(@拡張回答をご覧ください)。プラグインのパッケージの ''を1つしか持たない小さなxmlであっても、プラグイン**やそれ以外はどこにもありません。それは、自分自身を最もよく知っているプラ​​グインであり、それ自体を設定する方法を知っています。コアモジュールは、プラグインの存在を認識すべきではありません。それは、自分自身の設定を 'ApplicationContext'に加える可能性を提供するだけです。 – Roadrunner

    2

    サーバを再起動した場合、JARをWEB-INF/libに追加してCLASSPATHに追加するだけの理由はありません。カスタムクラスローダーとコンテキストリスナーの複雑さは、Springのコントロール下で他のクラスと同じように扱われるので、すべての複雑さがなくなります。

    WARを開いたり変更する必要がないため、このようにした場合は、それをserver/libディレクトリに配置してください。サーバークラスローダがそれを受け取るようにします。これにより、すべての配備されたアプリケーションですべてのプラグインクラスを利用できるようになります。

    答えは、別個の/プラグインディレクトリの重要性によって決まります。それが解決策の鍵で、サーバーの/ libディレクトリにJARを追加できない場合、それはそれです。私は何も持っていない。しかし、少なくともあなたが望むものを達成するための唯一の方法であることを確認する必要があるソリューションを再訪することは価値があると思います。

    +0

    これは常にオプションです。しかし、このアイデアは、戦争の中で(クラスパスではなく)いくつかの証明されたプラグインを持つことでした。ユーザーは、アプリケーションの外にある設定値に基づいてプラグイン1つまたはプラグインを読み込むことができました。そうすれば、平均的なユーザーは、プラグインシステムの内部ではなくconfigプロパティだけを気にする必要があります。 – Langali