はじめに:昨年は、春のベーシック+ソースコードというブログの目標を達成するのに良い時期はありませんでした。昨年は比較的怠惰だったので、今年は苦労しているインターネット開発者と私の知識を共有できることを願っています。将来的にやりたい建築家の友達、インターネットの職場初心者から夫の濡れた人まで、一緒に進歩しましょう、とにかく、共有がどれほど重要かを教えてください、とにかく、何が悪いのかを指摘し、コードを見ていきましょう一緒に海!
私は各章の前提を作るためにここにいます。いくつかの公式用語を適用することは必ずしも標準ではありません。目的はすべての人に理解して明確にすることです。説明が適切でない場合は、メッセージを残すことができます。ありがとうございます。
1.単純なオブジェクトが作成される回数を制御する方法
前のセクションで、複雑なオブジェクトを作成する場合はFactoryBeanインターフェースを実装する必要があると述べました。isSingletonがtrueを返す場合は、一度だけ作成する必要があることを意味します。falseの場合は、複数の複雑なオブジェクトを作成する必要があります。 。各オブジェクトは異なります!
Accountクラスを定義し、これをxmlで記述します
<!-- 如果我们想对这个简单对象,控制次数,加个scope标签,为singleton,那么这个scope对象只会被创建一次--> <bean id="account" scope="singleton" class="com.chenxin.spring5.scope.Account"></bean>
スコープがシングルトンの場合、これは1回だけ作成されることを意味します。このラベルはデフォルトでは書き込まれません。つまり、デフォルトで1回だけ作成されるため、Springはデフォルトでシングルトン(シングルトン)を作成します。プロトタイプの場合は、複数の異なるオブジェクトを作成します。
<!-- 如果我们想对这个简单对象,控制次数,加个scope标签并且等于prototype,那么这个scope对象只会被创建多次--> <bean id="account" scope="prototype" class="com.chenxin.spring5.scope.Account"></bean>
2.複雑なオブジェクトが作成される回数を制御する方法
複雑なオブジェクトを作成する場合は、FactoryBeanインターフェースを実装する必要があります。isSingletonがtrueを返す場合は、一度だけ作成する必要があります。falseの場合は、複数の複雑なオブジェクトを作成する必要があります。
次に、インスタンスファクトリか静的ファクトリかを尋ねる学生がいます。isSingletonメソッドを実装していなくても、実際にはスコープを使用してオブジェクトの作成数を制御しています。
3.オブジェクトの作成数を制御する必要があるのはなぜですか
一部のオブジェクトは共有できるため、一度作成するだけで済みます。一部のオブジェクトは全員で共有できないため、オブジェクトの特性に応じてこのオブジェクトを管理し、条件を作成する必要があります。
利点:リソースの不要な無駄を節約します
- 一度作成すればよいのはどのようなオブジェクトか
1、SqlSessionFactory
2. DAO(データを挿入するので、私もデータを挿入します。私たちはすべて挿入メソッドであり、違いはありません)
3.サービス(ログインする必要があり、ログインする必要があります。私たちの違いは、ユーザー名またはその他の入力パラメーターですが、方法は同じで、同じことを行います)
- どんな種類のオブジェクトを新しく作成する必要があるか
1、接続
2. Sqlsession、セッションセッション
3、Struts2アクション
4.オブジェクトのライフサイクル
1.オブジェクトのサイクルは何ですか
オブジェクトの作成、存続、および消滅の完全なプロセスを指します
2.オブジェクトのライフサイクルを研究する理由
当初、オブジェクトの作成はnewによって作成されたことがわかっています。このオブジェクトは、常に参照されるときに常に仮想マシンに存在します。コードと仮想マシンは、このオブジェクトのライフサイクルを管理します。
そのため、今日話しているオブジェクトの生存と死のプロセスは、私たちによって制御されるのではなく、Springに渡されて制御されます。オブジェクトのライフサイクルをよりよく理解すれば、実際には、Springのオブジェクトをより有効に活用できます。私たちのために創造します私たちのために何かをしに来てください
3.ライフサイクルの3つの段階
- 作成フェーズ
Springファクトリはいつオブジェクトの作成に役立ちますか?状況によって
1.オブジェクトが1回だけ作成される場合、つまりscope = "singleton"の場合、オブジェクトはSpringファクトリの作成と同時に作成されます。
2.オブジェクトが複数回作成される場合、つまりscope = "prototype"の場合、Springファクトリはオブジェクト(ctx.getBean)を取得し、同時にオブジェクトを作成します。
一度作成した場合:
<bean id="account" class="com.chenxin.spring5.Account"> </bean>
エンティティクラス
public class Account { private Integer id; private String name; public Account() { System.out.println("Account.Account"); } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Account{" + "id=" + id + ", name='" + name + '\'' + '}'; } }
テスト、scope = "singleton"またはBeanスコープタグが書き込まれていない場合、デフォルトオブジェクトは1回だけ作成され、ファクトリが新しい場合は、コンストラクタを呼び出してオブジェクトを作成する必要があります
@Test public void test1(){ ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml"); // Account account = (Account) ctx.getBean("account"); // System.out.println("account = " + account); }
Account.Account
scope = "prototype"の場合、オブジェクトは複数回作成され、ファクトリはgetBean時にオブジェクトを作成するのに役立ちます。
<bean id="account" scope="prototype" class="com.chenxin.spring5.Account"> </bean>
@Test public void test1(){ ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml"); Account account = (Account) ctx.getBean("account"); // System.out.println("account = " + account); }
したがって、ファクトリがオブジェクトの作成にいつ役立つかを明確に理解できます。
次に、この時点でscope = "singleton"に参加しますが、ファクトリの作成時にオブジェクトを作成するのを手伝いたくありません。Beanを取得したときにオブジェクトを作成する必要があります。今回はどうすればよいですか?
それでは、これを実行しましょう。ラベルlazy-init = "true"を追加するだけで済みます。これは、遅延読み込みを意味します。
<bean id="account" scope="prototype" class="com.chenxin.spring5.Account" lazy-init="true"> </bean>
このようにして、シングルトンを前提としてgetBeanを呼び出すことができ、ファクトリはオブジェクトの作成を開始します。
- 初期化フェーズ
初期化フェーズとは何ですか?
これは、Springファクトリがオブジェクトを作成した後、オブジェクトの初期化メソッドを呼び出して、対応する初期化操作を完了することを意味します。
1.初期化を提供するのは誰か:プログラマーは、初期化操作を完了するためのニーズに応じて初期化方法を提供します。
2.初期化メソッドを呼び出すのは誰か:Springファクトリは
Springには、初期化のための2つの方法があります。
1. InitializingBeanインターフェース:InitializingBeanのafterPropertiesSet()メソッドを実装する必要があります。初期化操作を完了するためのコードはこのメソッドで記述できます。Springインターフェースを実装しているため、Springは実装したインターフェースを見つけることができ、この方法;
public class Product implements InitializingBean { public Product() { System.out.println("Product.Product"); } /* * 这个就是初始化方法:做一些初始化的操作 * Spring会进行调用 */ public void afterPropertiesSet() throws Exception { System.out.println("Product.afterPropertiesSet"); } }
<bean id="product" class="com.chenxin.spring5.Product"></bean>
@Test public void test2(){ ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml"); }
したがって、出力結果は、オブジェクトが最初に作成され、コンストラクターが呼び出され、Springがオブジェクトを初期化することです。オブジェクトが初期化されていることがわかったら、InitializingBeanインターフェイスのafterPropertiesSetメソッドを実装します。これにより、初期化メソッドを呼び出すことができます。初期化用。
しかし、ここには問題があります。前の章を読んだ学生は、このInitializingBeanが、コードのスケーラビリティに適していないSpringフレームワークと結合されたFactoryBeanインターフェイスに似ていることを知っています。Springフレームワークを離れると、これらの初期化コードは使用できなくなったと思うので、柔軟にするために初期化のための別の戦略があります。
2.クラスで共通のメソッドを提供します
public class Cat { public Cat() { System.out.println("Cat.Cat"); } /** * 提供一个普通方法 */ public void myInit(){ System.out.println("Cat.myInit"); } }
Springに初期化メソッドの呼び出しを認識させたい場合は、構成ファイルで初期化メソッドを呼び出したいことだけをSpringに伝えることができます。これにより、後で別のフレームワークに変更しても、InitializingBeanインターフェイスを使用できなくなります。あなたコードはまだ使用可能です、少なくともそれはエラーを報告しませんInitializingBeanを見つけることができません
<bean id="cat" class="com.chenxin.spring5.Cat" init-method="myInit"></bean>
Cat.Cat Cat.myInit
このようにして、オブジェクトの初期化をより柔軟に制御できます。
詳細な分析:
オブジェクトがInitializingBeanを実装するだけでなく、通常の初期化メソッドmyInit()も提供する場合、実行の順序は何ですか?私たちはそれをテストします
public class Product implements InitializingBean {//不仅实现了InitializingBean public Product() { System.out.println("Product.Product"); } //还提供了普通的初始化方法 public void myInit(){ System.out.println("Product.myInit"); } /* * 这个就是初始化方法:做一些初始化的操作 * Spring会进行调用 */ public void afterPropertiesSet() throws Exception { System.out.println("Product.afterPropertiesSet"); } }
構成ファイルは、初期化方法も示しています
<bean id="product" class="com.chenxin.spring5.Product" init-method="myInit"></bean>
消す:
Product.Product Product.afterPropertiesSet Product.myInit
明らかに、afterPropertiesSetの初期化は、カスタム初期化myInitの前に実行されます。
したがって、オブジェクトの作成後に初期化メソッドが呼び出されることがわかっています。現時点では、一部の詳細を見落としています。この時点でプロパティを注入する必要がある場合は、この注入操作を最初に注入する必要があるとおっしゃいました。オブジェクトが作成されます。、または最初に初期化操作?
私たちはそれをテストします
public class Product implements InitializingBean { private String name; public void setName(String name) { System.out.println("Product.setName"); this.name = name; } public Product() { System.out.println("Product.Product"); } public void myInit(){ System.out.println("Product.myInit"); } /* * 这个就是初始化方法:做一些初始化的操作 * Spring会进行调用 */ public void afterPropertiesSet() throws Exception { System.out.println("Product.afterPropertiesSet"); } }
<bean id="product" class="com.chenxin.spring5.Product" init-method="myInit"> <property name="name" value="chenxin"></property> </bean>
このコードは、setメソッドにsetNameという文を追加します
Product.Product Product.setName Product.afterPropertiesSet Product.myInit
したがって、明らかに、セットインジェクションはオブジェクトが作成された後、初期化の前であるため、オブジェクトを作成することです->属性インジェクション->初期化
実際、この初期化インターフェイスafterPropertiesSetのメソッドの意味は、プロパティセットが挿入された後であり、初期化がセットの挿入の前であることも表しています。!
では、初期化操作とは何ですか?
実際、これはリソース、データベースリソース、ioリソース、ネットワークなどの初期化です。したがって、これらの関数は通常、このafterPropertiesSetで記述されます。
実際、後のアプリケーション初期化フェーズはまだ比較的少ないです。
- 破壊段階
Springがオブジェクトを破棄する前に、オブジェクトの破棄メソッドを呼び出して破棄操作を完了します
1. Springはいつ作成されたオブジェクトを破棄しますか?
ctx.close();は、ファクトリが閉じていることを意味します
破壊方法は、プログラマーが自分のニーズに応じて破壊方法を定義することです。これは、Springファクトリによって呼び出されます。
Springはオブジェクトを破壊するためにどのような方法を提供しますか?(実際には、初期化と非常によく似ています)
1.DisposableBeanインターフェースを実装します
public class Product implements InitializingBean, DisposableBean { private String name; public void setName(String name) { System.out.println("Product.setName"); this.name = name; } public Product() { System.out.println("Product.Product"); } public void myInit(){ System.out.println("Product.myInit"); } /* * 这个就是初始化方法:做一些初始化的操作 * Spring会进行调用 */ public void afterPropertiesSet() throws Exception { System.out.println("Product.afterPropertiesSet"); } @Override public String toString() { return "Product{" + "name='" + name + '\'' + '}'; } /** * 实现销毁方法,资源释放的操作 * @throws Exception */ public void destroy() throws Exception { System.out.println("Product.destroy"); } }
@Test public void test3(){ ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml"); Product product = (Product) ctx.getBean("product"); System.out.println("product = " + product); }
その結果、オブジェクトが作成、挿入、初期化されていることがわかりますが、なぜ破棄されないのですか?
Product.Product Product.setName Product.afterPropertiesSet Product.myInit
ファクトリが閉じられたときにオブジェクトの破棄が検出されるため、ctx.close()が必要です。closeメソッドは、ApplicationContextインターフェイスでは使用できないClassPathXmlApplicationContextの親クラスであるAbstractApplicatonContextに実装されているため、次のようにする必要があります。それを変更
@Test public void test3(){ // ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml"); ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml"); Product product = (Product) ctx.getBean("product"); System.out.println("product = " + product); ctx.close(); }
その結果、破壊方法を印刷することができます!
2.一般的な方法を定義する
myDestory()と呼ばれるProductで破棄メソッドを定義することもできます。
public void myDestory(){ System.out.println("Product.myDestory"); }
<bean id="product" class="com.chenxin.spring5.Product" init-method="myInit" destroy-method="myDestory"> <property name="name" value="chenxin"></property> </bean>
同様に、印刷順序も最初にSpring自身のファミリであり、次にそれをカスタマイズします。
Product.Product Product.setName Product.afterPropertiesSet Product.myInit product = Product{name='chenxin'} Product.destroy Product.myDestory
詳細な分析:
破棄メソッドの操作は、scope = "singleton"のメソッドにのみ適用できます。プロトタイプの場合、効果はありません。オブジェクトは毎回作成されるため、どちらを破棄する必要があるかわかりません。 、だから私はそれを春の工場として理解しています。私はあなたのためにそれを破壊しません。
実際、破壊操作が開発で使用されることはめったにないので、理解できます。
オブジェクトのライフサイクルは次の図に要約されています。
1.最初にSpringファクトリを作成し、Beanタグがシングルトンオブジェクトか非シングルトンオブジェクトかを確認してから、さまざまなタイミング(レイジーかどうか)に従ってオブジェクトの構築メソッドの呼び出しを開始し、反映してオブジェクトを作成します
2.作成後にDI操作と属性注入を実行します
3.次に、初期化メソッドの呼び出しを開始します
4.ファクトリを閉じて、destroyメソッドを呼び出します
5.構成ファイルのパラメーター化
構成ファイルのパラメーター化とは何ですか?Spring構成ファイルで頻繁に変更する必要のある文字列情報をより小さな構成ファイルに転送することを指します。
最初に質問させてください:
Spring構成ファイルに頻繁に変更する必要のある文字列はありますか?
もちろん、データベース接続関連のパラメーターなどもあります。Springの初期の頃、applicationContext.xmlの構成は数千行にもなりました。データベースの特定の構成がある場合、特定のコードが開発者にとって、それは正しいですか?この状況を知るのは簡単ですか?
さて、他に誰が開発について知っているかわからないと言うなら、あなたはビジネス上の接触が少なく、構造が小さいと思います。これが顧客向けの製品である場合、顧客は特定の構成を変更する必要があります。これらの構成ファイルを探し、特定の構成を見つけて、データベース構成情報を変更したいと言います。どこにありますか?
または、O&Mに任せて変更します。O&MはSpringを理解していません。彼がミスを犯した場合、落とし穴は誰ですか、それとも発展しませんか?それで、この変更された文字列を小さな構成ファイルに転送できますか?この場合、変更と保守は簡単ですか?
そのため、便宜上、この構成情報を個別に保存するための小さな構成ファイル(db.properties)を取り出します。このファイルは好きなように配置できます。ここの[リソース]の下に配置します。
jdbc.driverClassName = com.mysql.jdbc.Driver jdbc.url = jdbc:mysql://localhost:3306/users?useSSL=false jdbc.username = root jdbc.password = root
次に、Springはどのようにして構成ファイルを見つけることができると言いましたか?
そのような段落をxmlで書く必要があります
<context:property-placeholder location = "classpath:/db.properties"> </ context:property-placeholder><context:property-placeholder location="classpath:/db.properties"></context:property-placeholder> <bean id="conn" class="com.chenxin.spring5.factorybean.ConnectionFactoryBean"> <property name="driverName" value="${jdbc.driverClassName}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean>
これで、構成ファイルのパラメーター化操作は完了です。関連する構成パラメーターを後で変更する場合は、Spring構成ファイルで変更する必要はありません。
6.タイプコンバーター
Spring構成ファイルを介したプロパティインジェクションについて説明しました。Integerプロパティの値について、文字列の<value> </ value>タグを挿入することで、Integerのプロパティにインジェクトできるのはなぜですか。
実際、Springは、実際にはSpringの型コンバーター(コンバーターインターフェイス)である最下層で型変換を完了するのに役立ちました。複数のタイプの変換が含まれるため、インターフェイスはこの違いを保護するように定義されています。
したがって、Springが整数に文字列を与えるとき、それはStringToNumberと呼ばれる型コンバーターを介して行われます。
6.1、カスタムタイプコンバータ
Springが特定の型コンバーターを提供しておらず、プログラマーがそれをアプリケーションプロセスで使用する必要がある場合、プログラマーは型コンバーターを定義する必要があります。
Dateタイプの属性を持つPersonクラスを定義してみましょう
public class Person implements Serializable { private String name; private Date birthday; public void setName(String name) { this.name = name; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", birthday=" + birthday + '}'; } }
xml配置
<bean id="person" class="com.chenxin.spring5.converter.Person"> <property name="name" value="chenxin"></property> <property name="birthday" value="2020-04-05"></property> </bean>
テストカテゴリ:
@Test public void test4(){ ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml"); Person person = (Person) ctx.getBean("person"); System.out.println("person = " + person); }
エラーが報告されました。タイプ「java.lang.String」のプロパティ値をプロパティ「birthday」に必要なタイプ「java.util.Date」に変換できませんでした。これは、Springが文字列を日付タイプに変換できないことを示しています。提供しません。フォーマット、国によって日付フォーマットが異なるため、Springが表示されないため、今回はカスタムタイプコンバーターを使用します。
開発ステップ:
- クラスはConverterインターフェースを実装します
public class MyDateConverter implements Converter<String, Date> { public Date convert(String s) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date date = null; try { date = simpleDateFormat.parse(s); } catch (ParseException e) { e.printStackTrace(); } return date; } }
コードは完成しましたが、自分で定義した型コンバーターを見つけるようにSpringにどのように指示しますか?Springは、最初に定義したコンバーターオブジェクトを管理のためにSpringに渡して作成する必要があります。次に、このコンバーターは、これが通常のオブジェクトではないことをSpringに通知します。これはコンバーターです。ユーザーに登録するのを手伝ってください。変換する
- 春の経営陣によって作成されました
<bean id="myDateConverter" class="com.chenxin.spring5.converter.MyDateConverter"> </bean>
- Springに、コンバーターへの登録を手伝ってもらう必要があります。コンバーターのタイプはSetコレクションであり、カスタムオブジェクトです。refタグを使用する必要があります。
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <ref bean="myDateConverter"></ref> </set> </property> </bean>
idとconversionServiceは固定されており、気軽に書くことはできません。このConversionServiceFactoryBeanのプロパティを見て、なぜそれがsetタグであるのかを理解してください。
これは、変換、出力に役立ちます:person = Person {name = 'chenxin'、birthday = Sun Apr 05 00:00:00 CST 2020}
詳細:
1. ConversionSeviceFactoryBeanは、id属性値がconversionServiceでなければならないことを定義します
2. Spring Frameworkの組み込みの日付型コンバーター、日付形式:2020/05/01(サポートされていません:2020-05-01)
7.後処理Bean
後処理BeanのフルネームはBeanPostProcessorです。このコースは最初にドアに入り、後でaopについて説明するときに詳細に説明します。
機能:Springファクトリによって作成されたオブジェクトを再処理します
画像分析を見てみましょう:
1. Userユーザーの場合、Springがファクトリを作成した後、ユーザーとしてBean IDをスキャンし、このクラスのフルパスを取得してから、リフレクションを開始して構築メソッドを取得し、オブジェクトを作成します。
2.オブジェクトが作成された後、インジェクションが完了し、Springはこのオブジェクトを処理するための穴を残します。パラメータObject beanは新しく作成されたオブジェクトUserを表し、id値はbeanNameに与えられます。終了後処理中、処理済みオブジェクトを返しました
3. Springは処理されたオブジェクトを取得し、それを初期化します
4.初期化が完了したら、穴を残します。再度処理してから、Springに戻してBeanを形成します。
プログラマーは、BeanPostProcessorで指定されたインターフェースにメソッドを実装します。
1. Object postProcessBeforeInitiallization(Object bean String beanName)関数:Springがオブジェクトを作成し、それに注釈を付けた後、Beforeメソッドを実行してオブジェクトを追加し、Springによって作成されたオブジェクトを取得できます。メソッドのパラメーターは最終的に戻り値Springフレームワークに渡します
2. Object postProcessAfterInitiallization(Object bean String beanName)関数:Springがオブジェクトの初期化を完了した後、Afterメソッドを実行してオブジェクトを追加し、Springによって作成されたオブジェクトを取得できます。メソッドのパラメーターは最終的に戻り値に渡されます。価値。Springフレームワークに与える
実際の戦闘では、Springの初期化操作が処理されることはめったにありません。BeforeAfterを区別する必要はありません。Afterメソッドの1つを実装するだけで済みます。
開発ステップ:
1.クラスはBeanPostProcessorを実装し、プロセッサでperson.name = modifychexinを変更しました
ここで、BeanPostProcessorの場合、BeanPostProcessorはSpringで作成されたすべてのオブジェクトを追加することに注意する必要があります。!!!したがって、それが変更するオブジェクトであるかどうかを判断する必要があります
public class MyBeanPostProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(bean instanceof Person){ Person person = (Person) bean; person.setName("modify chenxin!"); } return bean; } }
2.構成ファイルセットname = chenxin、このポストプロセッサが初期化後に名前を変更するのに役立つかどうかを見てみましょう。
<bean id="person" class="com.chenxin.spring5.converter.Person"> <property name="name" value="chenxin"></property> <property name="birthday" value="2020-04-05"></property> </bean> <bean id="myBeanPostProcessor" class="com.chenxin.spring5.postprocessor.MyBeanPostProcessor">
結果は試してみることができます、それはchenxinを変更するために変更されている必要があります!
詳細に注意を払う必要があります
1. BeanPostProcessorは、Springで作成されたすべてのオブジェクトを追加します。!!!したがって、それが変更するオブジェクトであるかどうかを判断する必要があります
2. BeforeInitializationを操作してみませんか?花の太鼓と通過というものがあります。このプロセスは、各オブジェクトの最初から最後までのプロセスである必要があります。次に、前に私に与えたものを後で返す必要があるので、ここでそれを行います。豆を返します。この場合、以前に書いていなかっただけです。
興味があれば、通常の開発で試してみることができます。実装する必要があるのはAfter!だけです。
さて、私たちはこのセクションのためにここにいます、そして次のセクションはAopの章に向けて始まります!!!!