スプリングIOCプロトタイプ
スプリングフレームワークの基本的なコアと出発点は、間違いなくIOCです。 Spring Containersが提供するコアテクノロジーとして、IOCは依存関係の反転を正常に完了しました。メインクラスのアクティブな管理から、依存関係に関するアクティブな管理から、スプリングコンテナによる依存関係のグローバル制御まで。
これを行うことの利点は何ですか?
もちろん、それはいわゆる「デカップリング」であり、プログラムのモジュール間の関係をより独立させることができます。 Springは、これらのモジュール間の依存関係を制御し、コンテナの起動および初期化プロセス中にこれらの依存関係に基づいてこれらのモジュールを作成、管理、維持するだけです。モジュール間の依存関係を変更する必要がある場合は、プログラムコードを変更する必要さえありません。変更された依存関係を変更するだけです。 Springは、コンテナを再度開始および初期化するプロセスでこれらの新しい依存関係を再確立します。このプロセスでは、コード自体がモジュールの特定の依存関係の宣言を反映する必要はなく、必要なモジュールのインターフェイスを定義する必要があることに注意する必要があります。したがって、これは典型的なインターフェイス指向のアイデアです。同時に、構成ファイルまたは注釈の形で依存関係を表現することをお勧めします。関連するスプリング処理クラスは、これらの外部構成ファイルに基づいてモジュールを組み立てるか、注釈をスキャンして内部アノテーションプロセッサを呼び出してモジュールを組み立ててIOCプロセスを完了します。
IOCの目的は、DIと呼ばれる依存噴射です。 IOCテクノロジーを通じて、究極のコンテナは、モジュール間の依存噴射を完了するのに役立ちます。
さらに、最後のポイントは、スプリングIOCのプロセスでは、上記のメインラインについて常に明確にしなければならないということです。リアルタイムの構文とクラス構造がどれほど複雑であっても、その機能と目的は同じです。これは、記述された構成ファイルをアセンブリ「図面」として依存することにより、モジュールの「アセンブリ」を完了することです。複雑な構文は、この目的を達成するための単なる手段です。
いわゆるIOCプロトタイプは、最も単純なIOC概略図を表示するために、このプロセスを説明するために完全にシンプルなプロトタイプを作成することもできます。
まず、メインモジュールと2つのインターフェイスで定義された依存性モジュールなど、定義するいくつかのモジュールがあります。
クラスMainModule {Private DependModulea Modulea;プライベートDependModuleb moduleb; Public DependModulea getModulea(){return modulea; } public void setModulea(DependModulea modulea){this.modulea = modulea; } public Dependuleb getModuleb(){return moduleb; } public void setModuleb(DependModuleb moduleb){this.moduleb = moduleb; }} interface DependModulea {public void funcfrommodulea();}インターフェイスdeponemoduleb {public void funcfrommoduleb();} class DependModuleAimpl dependulea {@Override public void cfrommodulea(){System.out.out.out.out.out; " }} class DependModuleBimpl dependemoduleb {@override public void funcfrommoduleb(){system.out.println( "これはモジュールBからのfuncです"); }}IOCを採用せず、メインモジュール自体に依存して従属モジュールの作成を制御する場合、次のようになります。
public class simpleiocdemo {public static void main(string [] args)throws classNotFoundException {MainModule MainModule = new MainModule(); mainmodule.setModulea(new DependModuleAimpl()); mainmodule.setModuleb(new DependModuleBimpl()); mainmodule.getModulea()。funcfrommodulea(); mainmodule.getModuleb()。funcfrommoduleb(); }}これは、IOCコンテナプロトタイプの単純化された定義です。起動後にコンテナが初期化されると、ユーザーが作成した構成ファイルを読み取ります。ここでは、単純なプロパティ構成ファイルを例として使用します。ユーザーがGetBeanメソッドを呼び出す場合にのみ、対応するBeanは構成ファイルに従って真に組み立てられ、ロードされます。組み立てられた豆を保存するために使用されるマップは、定義したコンテナプロトタイプ内で維持されます。要件を満たす豆がある場合、再度作成する必要はありません。
クラスSimpleiOcContainer {private Properties Properties = new Properties();プライベートマップ<文字列、オブジェクト> moduleMap = new Hashmap <>(); {try {properties.load(new fileinputStream(new file( "simpleioc.properties"))); } catch(Exception e){e.printstacktrace(); }} public object getBean(String moduleName)classNotFoundException {object instanceobj; if(modulemap.get(moduleName)!= null){system.out.println( "return old bean"); return modulemap.get(moduleName); } system.out.println( "new Bean"); string fullclassname = properties.getProperty(modulename); if(fullclassname == null)throw new ClassNotFoundException(); else {class <?オブジェクト> clazz = class.forname(fullclassname); try {instanceobj = clazz.newinstance(); instanceobj = buildattachedmodules(modulename、instanceobj); modulemap.put(modulename、instanceobj); InstanceOBJを返します。 } catch(instantiationexception e){e.printstacktrace(); } catch(Illegalaccessexception e){e.printstacktrace(); }} nullを返します。 }プライベートオブジェクトbuildattachedmodules(string modulename、object instanceobj){set <string> propertieskeys = properties.stringpropertynames(); field [] fields = instanceobj.getClass()。getDeclaredFields(); for(string key:propertieskeys){if(key.contains(modulename)&&!key.equals(modulename)){try {class <?オブジェクト> clazz = class.forname(properties.getProperty(properties.getProperty(key))); for(field field:fields){if(field.getType()。isassignable from(clazz))field.set(instanceobj、clazz.newinstance()); }} catch(例外e){e.printstacktrace(); }}} return instanceobj; }}これは、Properties Configurationファイルを使用して書いた依存関係構成ファイルです。この構成ファイルは、アセンブリモジュールの「描画」です。ここの構文は、私たちによって完全に定義されています。実際のSpring IOCコンテナでは、より複雑な依存関係ロジックを表現するために、より開発されたXML形式の構成ファイルまたは新しい注釈設定が使用され、注釈プロセッサを使用して図面の分析を完了します。
mainModule = com.rocking.demo.mainmodulemainmodule.modulea = moduleamainmodule.moduleb = modulebmodulea = com.rocking.demo.demo.duleaimplmoduleb = com.rocking.demo.deptmodulebimpl
これがテストコードです。定義したIOCコンテナを介して要件を満たすモジュールを完全に取得できることがわかります。同時に、定義した容器がこれらの豆を私たちのために維持できることもわかります。豆が組み立てられて作成されたとき、再び作成する必要はありません。
public class simpleiocdemo {public static void main(string [] args)throws classNotFoundException {simpleioccontainer container = new SimpleIocContainer(); DependModuleA odulea =(deplymodulea)container.getBean( "modulea"); modulea.funcfromdulea(); DependModuleb moduleb =(deplymoduleb)container.getBean( "moduleb"); moduleb.funcfrommuleb(); MainModule MainModule =(MainModule)container.getBean( "Mainmodule"); mainmodule.getModulea()。funcfrommodulea(); mainmodule.getModuleb()。funcfrommoduleb(); container.getBean( "mainmodule"); }}これは、IOCの基本的なアイデアに基づいて作成したIOCコンテナプロトタイプです。 Spring IOCには複雑な構文がありますが、最終的に完了したタスクはコアで同じであり、いわゆる「すべての変更は本質から分離されません」。
スプリングIOC固有のプロセス
前回、IOCの一般的な実装のプロトタイプが示されました。では、メタデータメタ情報構成に基づいて、このコンテナのスプリングフレームワークにPOJOをロードするプロセスを具体的に実装する方法は? Spring IOCコンテナ作業プロセス全体には、非常に柔軟になるように設計された多くの場所があり、コンテナの機械的プロセスを完了するのではなく、独自のタスクを完了するための多くのスペースをユーザーに提供します。
これは、IOCコンテナ作業プロセス全体のプロセス図です。
1.コンテナ起動段階(1)構成ファイル情報の読み込み(2)構成ファイル情報の分析
(4)最初に後処理で、構成ファイルや注釈やJavabeanクラス情報などのメタ情報がIOCコンテナにロードされます。コンテナはXML-Format構成ファイルを読み取ります。この構成ファイルは、ユーザーと特別な注意が必要なアセンブリによって宣言された依存関係です。これは、豆を組み立てるための初期の「外部図」です。コンテナ内の解析エンジンは、コンテナ内で認識できるビアンデファイニングに記述するテキスト形式の文字メタ情報を解析できます。反射メカニズムと同様のクラス構造になります。 Javabeansと構成ファイルを分析することで得られたこのビアンデフィットは、要件を満たすJavabeanを組み立てる基本的な構造を取得します。 BeanDefinitionに加えてBeanDefinitionを変更する必要がある場合、このポストプロセッシングが実行されます。後処理は、一般に、Spring FrameworkのBeanFactoryPostProcessorを介して処理されます。
前回使用した例を使用して、このbeanDefinitionの動作原理を説明します。3つの豆、メインモジュールのメインモジュール、依存性モジュールは、deploduleaとdependmodulebがあります。前者は、後者の2つのモジュールに依存します。構成ファイルでは、通常、次のような依存関係を宣言します。
<?xml version = "1.0" encoding = "utf-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id = "mainmodule"> <Propet name "> <modulea"> </property> <property name = "moduleb"> <ref bean = "moduleb"/> </property> </bean> <bean id = "modulea"> </bean> <bean id = "moduleb"> </bean> </bean>
これは、上記の構成ファイルへの標準的なBeanFactoryコンテナ(Spring IOCコンテナの実装の1つ)のアセンブリを示すプログラムです。
クラスMainModule {Private DependModulea Modulea;プライベートDependModuleb moduleb; Public DependModulea getModulea(){return modulea; } public void setModulea(DependModulea modulea){this.modulea = modulea; } public Dependuleb getModuleb(){return moduleb; } public void setModuleb(DependModuleb moduleb){this.moduleb = moduleb; }} interface DependModulea {public void funcfrommodulea();}インターフェイスdeponemoduleb {public void funcfrommoduleb();} class DependModuleAimpl dependulea {@Override public void cfrommodulea(){System.out.out.out.out.out; " }} class DependModuleBimpl dependemoduleb {@override public void funcfrommoduleb(){system.out.println( "これはモジュールBからのfuncです"); }} public class simpleiocdemo {public static void main(string [] args)throws classNotFoundException {defaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlbeanDefinitionReader Reader = new XmlbeanDefinitionReader(BeanFactory); reader.loadbeandefinitions( "beans.xml"); MainModule MainModule =(MainModule)BeanFactory.GetBean( "Mainmodule"); mainmodule.getModulea()。funcfrommodulea(); mainmodule.getModuleb()。funcfrommoduleb(); }}ここでは、構成ファイルとJavabeanが読み込まれ、解析されます。ここでは、BeanDefinitionの生成と使用プロセスが隠されています。これは、IOC内で実際に発生する一般的なプロセスです。
public class simpleiocdemo {public static void main(string [] args)throws classNotFoundException {defaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); AbstractBeanDefinition MainModule = new rootBeanDefinition(MainModule.Class); AbstractBeanDefinition ModuleA = new rootBeanDefinition(DependModuleAimpl.class); AbstractBeanDefinition ModuleB = new rootBeanDefinition(DependModuleBimpl.Class); beanfactory.registerbeandefinition( "mainmodule"、mainmodule); beanfactory.registerbeandefinition( "modulea"、modulea); beanfactory.registerbeandefinition( "moduleb"、moduleb); MutablePropertyValuesプロパティバリュー= new MutablePropertyValues(); PropertyValues.Add( "modulea"、modulea); PropertyValues.Add( "moduleb"、moduleb); mainModule.setPropertyValues(PropertyValues); MainModule Module =(MainModule)BeanFactory.GetBean( "Mainmodule"); module.getModulea()。funcfrommodulea(); module.getModuleb()。funcfrommoduleb(); }}XMLのメタ情報を読み込んで読み取った後、IOC解析エンジンは、その実際のタイプに基づいて、その中に記載されているモジュールをBeanDefinitionに作成します。このビアンデファイニングは、反射またはプロキシプロセスと見なすことができます。目的は、IOCコンテナに、将来作成されるインスタンスオブジェクトの豆構造をクリアし、これらの豆構造をBeanFactoryに登録し、メインモジュールの依存関係をメインモジュールのプロパティにセッター注入の形で追加することです(これは、Main Moduleによって提供されたメインモジュールによって提供されたメインモジュールによって提供された方法で提供された方法に依存します)。すでに形になった。その後、GetBeanメソッドに電話して、要件を満たす豆を生産してください。これはプロセスの次の段階であり、後で説明します。
BeanFactoryへのBeanDefinitionの「描画」に関する情報を登録した後、登録されたBeanDefinitionに変更を加えることができます。これは、前述のユーザーの春のデザインの柔軟な側面の1つです。それは、すべてのプロセスが制御できないという意味ではありませんが、ユーザーが多くの場所でプレイするための多くのスペースを残しています。特定の方法は、BeanFactory Processor BeanFactoryPostProcessorを使用してBeanFactoryの処理に介入して、変更する必要があるBeanDefinitionパーツをさらに書き直すことです。このプロセスは、プロセスの「後処理」プロセスに対応します。
一般的なプロセッサのいずれかを使用します。属性プレースホルダー構成プロセッサを例として、登録されたBeanFactoryを構築した後に処理するため、対応するBeanDefinition属性の内容が構成プロセッサ指定された構成ファイルの情報に変更されます。
DefaultListableBeanFactory BeanFactory = new DefaultListableBeanFactory(); XmlbeanDefinitionReader = new XmlbeanDefinitionReader(BeanFactory); Reader.LoadBeanDefinitions(new ClassPathResource( "Beans.xml")); new ClassPathResource( "about.properties")); configurer.postprocessbeanfactory(beanfactory);
BeanFactoryPostProcessorはBeanFactoryを処理します。その結果、BeanDefinitionで定義されているいくつかの属性をBeanFactoryPostProcessorの場所にあるいくつかの情報に変更します。
2。Beanインスタンス段階
BeanDefinitionの処理された「内部図面」のガイダンスの下で、コンテナは、反射またはCGLIBの動的バイトコード生成を介してメモリに存在するアクティブ化されたインスタンスオブジェクトにビアンデファイフィーションをさらに変換し、ビアンデフィニッションによって指定された依存関係オブジェクトを新しく作成したインスタンスオブジェクトに、セッター注入または初期化を介して組み立てます。ここでは、依存関係オブジェクトの参照は、実際に依存する必要があるオブジェクト属性に割り当てられます。
しかし、ここで作成されたインスタンスは、単なるビーンの定義の単純なインスタンスではなく、春に包まれたビーンライターインスタンスであることに注意する必要があります。 BeanWrapperメソッドでBeanを包むために使用する必要があるのはなぜですか? BeanWrapperは、Beanプロパティに均一にアクセスするためのインターフェイスを提供しているためです。基本的なBeanフレームワークを作成した後、その中のプロパティを設定する必要があります。各豆のセッターメソッドは異なるため、反射で直接設定すると非常に複雑になります。したがって、Springはこのラッパーを提供して、プロパティ設定を簡素化します。
beanwrapper beanwrapper = new beanwrapperimpl(class.forname( "com.rocking.demo.mainmodule")); beanwrapper.setPropertyValue( "modulea"、class.forname( "com.rocking.demo.depmoduleaimpl"); newinstance(); "moduleb"、class.forname( "com.rocking.demo.depmodulebimpl")
上記のプロセスは、春には、クラスの反射容器を取得してパッケージを作成することにより、将来包まれているインスタンスビーンの構造を理解できることを示しています。 Unified Property Setting Method SetPropertyValueを使用して、このパッケージのインスタンスのプロパティを設定します。取得した最終的なBeanインスタンスは、getWrappingInstanceを介して取得され、その属性が正常に割り当てられていることがわかります。
現時点では、Beanインスタンスは実際には完全に使用可能ですが、Springは、この段階でのユーザーの介入を完了するために、インスタンス段階で私たちのための柔軟な戦略を準備しました。 BeanFactoryPostProcessorコントロールコンテナの起動段階でのBeanDefinitionと同様に、インスタンス化段階で、Springは、可能な変更を完了するために組み立てられたインスタンスを動作させるためのビーンポストプロセッサプロセッサを提供します。
以下は、BeanPostprocessorの実装クラスを定義し、プロセッサフテレニタレーション後の方法を実装し、Bean Instance Assemblyの後と前に個別に実行される操作を定義する方法を実装する方法を実装していることを示します。 BeanFactoryがこのプロセッサを追加した後、GetBeanメソッドが組み立てられるたびに、2つの方法が「図面」(アセンブリプロセス中に作成された依存インスタンスBeanを含む)に従って組み立てられたBeanインスタンスで呼び出されます。これらの方法は、これらの豆インスタンスを変更できます。
このような例は次のとおりです(メインモジュールとその依存関係は、この記事の以前のものと同じです):
class modulec {private string x; public string getx(){return x; } public void setx(string x){this.x = x; }} class modulePostProcessorを実装するbeanpostprocessor {@Override public object postprocessafterinitialization(object object、string string)throws beansexcection {system.out.println(string); if(object instanceof modulec){system.out.println(string); ((modulec)object).setx( "after"); }オブジェクトを返します。 } @Override public Object postprocessbeforeInitialization(object object、string string)throws beansexception {(object instanceof modulec){((modulec)object).setx( "before"); }オブジェクトを返します。 }} public class verysimpleiockernal {public static void main(string [] args)throws classNotFoundException、BeanSeexception、InstantiationException、Illegalaccessexception {defaultListableBeanFactory = new DefaultListableBeanFactory(); XmlbeanDefinitionReader Reader = new XmlbeanDefinitionReader(BeanFactory); Reader.LoadBeanDefinitions(new ClassPathResource( "Beans.xml")); modulePostProcessor PostProcessor = new modulePostProcessor(); BeanFactory.AddBeanPostProcessor(PostProcessor); MainModule Module =(MainModule)BeanFactory.GetBean( "Mainmodule"); modulec modulec =(modulec)beanfactory.getbean( "modulec"); System.out.println(modulec.getx()); }}これは、Beanの依存関係構成ファイルです。
<?xml version = "1.0" encoding = "utf-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring/spring-benss.xsd" <プロパティ名= "modulea"> <ref bean = "modulea"/> </property> <property name = "moduleb"> <ref bean = "moduleb"/> </property> </bean> <bean id = "modulea"> <プロパティ名= "infoa"> <値> $ {modulea.infoa} <プロパティ名= "infob"> <value> moduleBの情報</value> </jeppert> </bean> <bean id = "modulec"> </bean> </bean>最終結果から、GetBeanメソッドを呼び出すことによって取得されたGetBeanインスタンス(依存関係によって生成される)が、前処理および後処理のためにBeanPostProcessorによって取得されることがわかります。
上記のビーンポストプロセッサと同様の組み立てられた豆を処理することに加えて、Springは、init-methodとDestroy-methodを構成することにより、豆の初期化と破壊プロセスのコールバック関数を設定することもできます。これらのコールバック関数は、Beanインスタンスを変更する機会を柔軟に提供することもできます。
Spring IOCプロセス全体は、実際には、私たちが書いたIOCプロトタイプと本質的に同じです。ただし、複雑な設計により、IOCプロセスがユーザーにより柔軟かつ効果的なスペースを提供できることを除きます。さらに、SpringのIOCは、セキュリティ、コンテナ安定性、およびメタデータから豆から変換効率の点で絶妙な設計を達成し、Spring容器であるIOCの基礎を安定させています。