ホームページ >Java >&#&チュートリアル >SPI を使用して Java でデカップリングを実現する方法
SPI の正式名は Service Provider Interface で、フレームワークの拡張機能やコンポーネントの置き換えを開始するために使用できます。
本質は、インターフェイス実装戦略モード構成ファイルを使用して実装クラスを動的にロードすることです。
具体的な使用方法では、いくつかの規則があります。
(1) インターフェースのフルネームファイルは、classPath
# の META-INF/services/ 配下に作成されると規定されています。 ## (2) このファイルには、インタフェース実装クラスのフルネーム(パスファイル名)を記述します(実装クラスが複数ある場合は、行を分けて記述します)。 (3) 2を利用する場合は、java.util.ServiceLoaderのload(Interface.class)で実装クラスを取得することで利用可能になります。 インターフェイス実装クラスにはパラメーターのないコンストラクターが必要であることに注意してください。 実装ケースこのアプリケーションでは、A モジュールと B モジュールの 2 つのモジュールがあり、この 2 つのモジュールのうち、A モジュールがメイン モジュール、B がスレーブ モジュール、B モジュールが存在します。モジュールはモジュール A に依存します。しかし現在、モジュール B に実装されているクラスが存在します。モジュール A はこのクラスの関数を呼び出す必要があり、モジュールはモジュール B に依存できなくなります。この時点で、デカップリングが必要です。この実装では、デカップリング実装に SPI が使用されます。具体的な実装計画は次のとおりです: (1) モジュール A に新しいインターフェイスを作成します: MyLogAppender. 具体的な実装は次のとおりです:/** * @author Huang gen(kenfeng) * @description 自定义的appender接口 * @Since 2021/02/21 **/ public interface MyLogAppender { /** * 获取实现的appender * @return 返回新建的appender对象 * */ Appender getAppender(); }このインターフェイスは非常に単純で、アペンダー オブジェクトを返すだけです。オブジェクトの実際の操作については、インターフェースの実装内で操作が実行されます。 (2) このインターフェイスの実装をモジュール B に追加します。具体的な操作は次のとおりです。
/** * @author Huang gen(kenfeng) * @description 自定义的appender * @Since 2021/02/21 **/ @Component public class MeshLogAppender extends UnsynchronizedAppenderBase<ILoggingEvent> implements MyLogAppender,ApplicationContextAware { private ApplicationContext applicationContext; public MeshLogAppender(){ } @Override public Appender getAppender() { MeshLogAppender meshLogAppender = new MeshLogAppender(); return meshLogAppender; } @Override protected void append(ILoggingEvent iLoggingEvent) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String std = simpleDateFormat.format(new Date(Long.parseLong(String.valueOf(iLoggingEvent.getTimeStamp())))); String log = std + "\t" + iLoggingEvent.getLevel() +"\t"+"--- ["+ iLoggingEvent.getThreadName()+"]\t"+iLoggingEvent.getCallerData()[0]+":\t "+iLoggingEvent.getMessage(); FlowMessage input = new FlowMessage(); MeshFlowService meshFlowService = SandboxSystemServiceFactory.getService(MeshFlowService.class); Map<String, Object> body = new HashMap<>(2); body.put("log",log); input.setTenantCode(DefaultTenant.get()); input.setAppCode("epoch"); input.setFlowCode("log_broadcast"); input.setBody(body); FlowMessage output = meshFlowService.process(input); if(!StringUtils.isEmpty(output.getErrorMessage())){ throw new RuntimeException("发布日志时,广播失败"); } } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }このインターフェイスの宣言とインターフェイスの実装には、いくつかの小さなトリックがあります。埋め込む。インターフェースではクラスの取得が宣言されているだけで、具体的なメソッドは実装されていません。実装クラスでは、このクラスをインスタンス化し、新しいクラスを作成して返しますが、このとき、ユーザーはこの get メソッドに従って実装クラスを取得し、実装クラスに対して何らかの操作を実行できます。この方法で記述すると、次の 2 つの利点がもたらされます: i. コードがより簡潔になり、インターフェイス コードがシンプルで理解しやすくなります ii. 一部のパラメータを実装クラスの構築メソッドに注入できます。 get メソッドに直接注入できます。 (3) 実装クラスが配置されているフォルダー (sandbox-app-epoch-starter) に構成ファイルを追加します。構成ファイルのデフォルトのパスは、resources/META-INF/services です。 /, in このフォルダーに新しい質問を作成します。ファイル名はインターフェイスへのパス、内容は実装クラスへのパスです。これから、インターフェース-->実装クラスのマッピングを実装できます。 上の図に示すように、ファイル名は com.alibaba.halo.sandbox.app.util.MyLogAppender ファイルの内容は com.alibaba.lattice2 です。 epoch.util.MeshLogAppender原則として、ユーザーがインターフェイスを使用すると、プロジェクト内のすべてのファイルがスキャンされ、ファイル名は com.alibaba.halo.sandbox.app.util.MyLogAppender になります。関連する実装クラス (4) A では、インターフェイスを直接使用して呼び出しを行うことができます。具体的な実装は次のとおりです:
ServiceLoader<MyLogAppender> myLoaderInterfaceServiceLoader = ServiceLoader.load(MyLogAppender.class); Iterator<MyLogAppender> myLoaderInterfaceIterator = myLoaderInterfaceServiceLoader.iterator(); while (myLoaderInterfaceIterator.hasNext()){ MyLogAppender myLoaderInterface = myLoaderInterfaceIterator.next(); Appender newAppender = myLoaderInterface.getAppender(); newAppender.setName("application"); newAppender.setContext(loggerContext); newAppender.start(); rootLogger.addAppender(newAppender); }As上記からわかるように、これを使用して MyLogAppender インターフェイスを直接呼び出すことができ、インターフェイスを通じて取得した Appender を後で直接割り当てることができます。 メリットとデメリットメリット: コードの分離が実現可能デメリットは、実装クラスが複数ある場合、インスタンスの取得にパラメーターやフラグを渡すことができないことです。トラバーサルを通じてのみ取得でき、遅延読み込みは実装できません
以上がSPI を使用して Java でデカップリングを実現する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。