スプリングコアテクノロジー
**前提コースの要件:** このチュートリアルを視聴する前に、「JavaWeb」および「Java 9-17 新機能」ビデオ チュートリアルを完了してください。
**推奨事項:** Java 開発にあまり慣れていない学生の場合は、半月から 1 か月かけて小さなプロジェクトを多数書くのが最善です。一度にすべてを学ぶことはお勧めできません。前回の内容とほぼ同じ内容 次元削減攻撃です 以前に学んだ基礎知識を一気に学習すると忘れてしまいがちです、特にJavaSE段階の内容は。
このビデオは 2021 年版の SSM チュートリアルとは異なり、再版されたバージョンです。ビデオで学習した Spring Framework のバージョンは: 6.0 です。
SSM (Spring+SpringMVC+Mybatis) の学習ステージに無事に入った皆さん、おめでとうございます。Java Newbie Village も無事に終了できました。以前に Mybatis をすでに学習しているため、このチュートリアルのタイム スケジュールは以前より短くなります。ここからは、多くの概念を理解するのが少し難しくなります。エンタープライズ開発シナリオに慣れていないため、そのような考え方のメリットを実感するのは困難です。後の段階でも、ほぼすべての概念が理解できるようになります。ビッグデータ理論(現在最も人気のある最先端のテクノロジー)を実現するためのフレームワークは、コンピューターの基本ではなく、いかに効率的に作業するかに関係するようになってきています。
JavaWeb 段階では、Java を使用した Web アプリケーション開発の方法を学び、Web サイトを構築できるようになりました。しかし、開発のプロセスでは、多くの不便なことがわかりました。最終的なライブラリの実際のプログラミングでは、管理システムについては、明確なアイデアがあり、対応するインターフェイスの書き方を知っているにもかかわらず、開発効率が非常に遅く、オブジェクト作成の管理に多くの欠陥があることがわかりました。そのため、フレームワークを継続する必要があります。 Java 開発を簡素化し、標準化するテクノロジー。
Spring はそのようなフレームワーク (ドキュメント: https://docs.spring.io/spring-framework/docs/6.0.4/reference/html/core.html#spring-core) であり、開発を簡素化するように設計されています。軽量IoCおよびAOPコンテナ フレームワーク 主にBeanのライフサイクルを管理する軽量コンテナであり、そのエコロジーは非常に大きく発展しました。それで、まず第一に、IoCとAOP、そしてBean とは何ですか? 恐れることはありません。これらの概念は高級感に満ちているように聞こえますが、実際にはそれほど高度ではありません(これは多くのことに当てはまります。名前は素晴らしく聞こえますが、実際には理解するのが簡単なだけです)。
IoCコンテナの基本
Spring フレームワークの中核は実際にはその IoC コンテナであり、これが Spring の学習を開始するための最初の目的地となります。
IoC理論の紹介
以前の図書館管理システム Web アプリケーションでは、実際にはプログラム全体がさまざまな部分に依存して相互に連携して操作を完了していることがわかりました。たとえば、貸出情報の一覧を表示したい場合、最初にサーブレットを使用する必要があります。リクエストとレスポンスのデータを処理します。その後、リクエストされたすべてのデータは、処理のために対応するサービス (ビジネス層) に渡されます。サービスは、データベースからデータを取得する必要があると判断すると、対応するマッパーへのリクエストを開始します。
それらは互いに接続された歯車のようなもので、誰も他方なしでは生きていけません。
チームのように全員が明確に分業し、組み立てラインの一連の作業が連動する、高度に連成されたシステムです。
このようなシステムのロジックは非常に明確で、プロセス全体をすぐに理解できますが、非常に深刻な問題があります。私たちの時代は、実際にはソフトウェア プロジェクトが高速に反復される時代です。多くのアプリが行き来していることがわかります。 1日おきに更新し、今一番人気のある機能があれば、ノンストップで開発をフォローしていきますので、以前に書いたコードや実装した機能が必要になることがよくあります。パイプライン上の一部のモジュールを変更する必要はありませんが、そのような変更はパイプライン全体の参照関係の大規模な更新に直結します。
たとえば、次のような状況です。
class A{
private List<B> list;
public B test(B b){
return null;
}
}
class C{
public C(B b){
}
}
class B{
}
A と C が B を直接大量に使用していることがわかりますが、ある日、B の実装が古くなり、D が機能をより適切に実装するようになり、この新しいクラスを使用して業務を完了する必要があります。得たもの:
ご覧のとおり、クラス間の相関が強すぎるため、大規模にエラーが発生し始めます。以前は B を使用していたすべてのクラスを 1 つずつ変更する必要があり、すべて D に変更されます。単なる災害です!
以前に JavaWeb 段階で作成した実際のプロジェクトを含め、特定の Service 実装クラスを使用せず、別の実装クラスを使用してこれらの機能を異なるロジックで実行したい場合、現時点では次のことしかできません。修正は、プロジェクトが特に大規模な場合、クラス名の変更に伴う修正だけでも 1 日あれば十分です。
したがって、高結合によって引き起こされる欠点は明らかであり、現代のソフトウェア開発においては致命的な問題でもあります。この状況を改善したい場合は、各モジュールを分離して、モジュール間の依存関係がそれほど強くならないようにするしかありません。つまり、Service の実装クラスは私たちが決めるのではなく、プログラム自身が決めることになり、実装クラスのオブジェクトはすべてプログラムによって管理され、すべてのオブジェクト間の関係もプログラムによって動的に決定されます。 IoC理論が導入されました。
IOC は Inversion of Control の略語で、「制御の反転」と訳されます。IOC は、複雑なシステムを連携するオブジェクトに分解します。これらのオブジェクト クラスがカプセル化された後、内部実装は外部に対して透過的になるため、問題解決の複雑さが軽減されます。 . 、柔軟に再利用および拡張できます。
オブジェクトをIoCコンテナに渡して管理することができ、例えばインターフェースの実装が必要な場合、設定ファイルに基づいてどの実装クラスを与えるかを決定してくれるので、心配する必要がなくなります。どれを使いたいか、実装クラスだけ気にすればいいです 与えられたものは普通に使える実装クラスでなければなりません 使えればそれで終わりです とにかく調整するだけですこのように、一人が安心してビュー層のコードを書き、一人がビジネス層のコードを書くと、開発効率が非常に高くなります。
これは以前と同じコードですが、IoC コンテナーのサポートが追加されています。
public static void main(String[] args) {
A a = new A();
a.test(IoC.getBean(Service.class)); //瞎编的一个容器类,但是是那个意思
//比如现在在IoC容器中管理的Service的实现是B,那么我们从里面拿到的Service实现就是B
}
class A{
private List<Service> list; //一律使用Service,具体实现由IoC容器提供
public Service test(Service b){
return null;
}
}
interface Service{
} //使用Service做一个顶层抽象
class B implements Service{
} //B依然是具体实现类,并交给IoC容器管理
特定の実装クラスが変更された場合、新しい実装クラスを IoC コンテナ管理に引き渡すだけでよいため、以前のコードを変更する必要はありません。
interface Service{
}
class D implements Service{
} //现在实现类变成了D,但是之前的代码并不会报错
このように、基盤となる実装クラスが変更されても、それに関連するクラスではエラーが発生せず、大規模な変更が行われることになりますが、抽象化+コンテナ管理を定義することで、元の強い関連付けを解消することができます。
高い凝集性と低い結合性が現代のソフトウェア開発の設計目標であり、Spring フレームワークはオブジェクト管理用の IoC コンテナを提供します。オブジェクトは Spring IoC コンテナによってインスタンス化され、組み立てられ、管理されます。私たちはそれを Bean と呼びます。
春のプロジェクト第一弾
まず、Spring を使用する主な目的は、コードを単純化することではなく、ソフトウェア プロジェクトを分離することであることを明確にする必要があります。このパートでは、Spring の基本的な使用法を体験します。
Spring は独立したフレームワークではなく、実際には多くのモジュールが含まれています。
最初に学ばなければならないのは、コアコンテナモジュールである Core Container であり、Spring のコア技術を理解することによってのみ、このフレームワークがもたらす利便性を真に理解することができます。
Spring は、ツール ライブラリと同様、非侵入的なフレームワークです。既存のプロジェクトに簡単に追加できます。したがって、依存関係を直接インポートするだけで使用できます。Spring コア フレームワークの Maven 依存関係は次のように調整されます。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.4</version>
</dependency>
**注意:** チュートリアルの古いバージョンとは異なり、Spring 6 では Java バージョン17
10 以降を使用する必要があります。これには、後で SpringMvc を学習する場合も含め、Tomcat バージョンは 10 以降である必要があります。この依存関係には次の依存関係が含まれています。
ここに表示されるのは、Beans、Core、Context、SpEL および非常に重要な AOP フレームワークなどの Spring コア関連のコンテンツであり、この章ではそれらすべてについて説明します。
Spring フレームワークを使用しているときに次の警告が表示される場合:
12月 17, 2022 3:26:26 下午 org.springframework.core.LocalVariableTableParameterNameDiscoverer inspectClass 警告: Using deprecated '-debug' fallback for parameter name resolution. Compile the affected code with '-parameters' instead or avoid its introspection: XXXX
これは、LocalVariableTableParameterNameDiscoverer が Spring 6.0.1 バージョンで廃止としてマークされており、間もなく削除されるためです。Maven構成ファイルにコンパイル プラグインの
-parameters
コンパイル パラメーターを追加してください。<build> <pluginManagement> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.10.1</version> <configuration> <compilerArgs> <arg>-parameters</arg> </compilerArgs> </configuration> </plugin> </plugins> </pluginManagement> </build>
この問題が発生しない場合は、この部分を無視してください。
ここでは、最も単純な Spring プロジェクトを作成してみます。前にも述べたように、Spring は Bean を管理するための IoC コンテナを提供しますが、最初にこのコンテナの設定ファイルを作成する必要があります。設定ファイルをコンテナに渡すことができます。どの Bean を管理する必要があるか、および Bean のプロパティ、依存関係など。
まず、リソース内に test.xml という名前の Spring 構成ファイルを作成する必要があります (リソース内に作成されたファイルはコンパイル中にクラスパスに配置されます)。これは右クリックして作成できます。
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
この時点で、IDEA は、このファイルのアプリケーション コンテキストを構成していないことを示すプロンプトを表示します。ここで必要なのは、それを現在のプロジェクトとして指定することだけです。もちろん、これを構成するのは、コード プロンプトと依存関係を簡単に表示するためだけです。何も設定しないでください。何も影響しません。プログラムは引き続き正常に動作します。
ここでは、デフォルトの構成ポイントに従って確認するだけです。
Spring は、使用する必要があるオブジェクトを保存するための IoC コンテナを提供します。管理のためにオブジェクトを IoC コンテナに渡すことができます。オブジェクトを使用する必要があるときは、IoC コンテナに要求して決定させることができます。どのオブジェクトが私たちに与えられるのか。Spring が提供する IoC コンテナを使用する必要がある場合は、Bean のインスタンス化、構成、アセンブルを担当する IoC コンテナを表すアプリケーション コンテキストを作成する必要があります。
public static void main(String[] args) {
//ApplicationContext是应用程序上下文的顶层接口,它有很多种实现,这里我们先介绍第一种
//因为这里使用的是XML配置文件,所以说我们就使用 ClassPathXmlApplicationContext 这个实现类
ApplicationContext context = new ClassPathXmlApplicationContext("test.xml"); //这里写上刚刚的名字
}
たとえば、IoC コンテナを使用して Student オブジェクト (Bean) を管理し、このオブジェクトが必要なときにそれを適用できるようにする必要があります。まず、Student クラスを定義します。
package com.test.bean;
public class Student {
public void hello(){
System.out.println("Hello World!");
}
}
他の人にオブジェクトの管理を手伝ってもらいたいので、新しいオブジェクトを自分で作成することはできなくなりましたが、対応する設定を書きます。test.xml
作成したばかりのファイルを編集用に開き、以下を追加します。
<bean name="student" class="com.test.bean.Student"/>
ここでは設定ファイルに対応するBean情報を記述しておき、コンテナはここの設定に従って処理を行います。
さて、このオブジェクトはもう私たちが作成する必要はありませんが、IoC コンテナによって自動的に作成され、提供されます。作成されたオブジェクトをコンテキストから直接取得できます。
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
Student student = (Student) context.getBean("student"); //使用getBean方法来获取对应的对象(Bean)
student.hello();
}
実はここで取得した Student オブジェクトは Spring がリフレクション機構を使って作成したものなのですが、初心者にとってはなぜこのようなオブジェクトを作成するのか非常に混乱してしまうと思います。なぜ IoC コンテナ管理に任せるのでしょうか? 次の学習で徐々に理解していきます。
Beanの登録と設定
前回は、簡単な例を使用して、Spring を使用してオブジェクトを管理し、IoC コンテナーから管理対象オブジェクトをリクエストする方法を体験しました。このレッスンでは、Bean を Spring に登録する方法と、Bean の関連構成について詳しく学びます。
実際、多くの構成ファイルを作成でき、これらの構成ファイルは相互にインポートできます。
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<import resource="test.xml"/>
</beans>
ただし、簡単にするために 1 つの構成ファイルから始めます。まず、Bean を構成して登録する方法を知る必要があります。
Bean を設定するには、以下を追加するだけです。
<bean/>
しかし、このように書くと、Spring は設定したい Bean がどのクラスであるかを知ることができないため、対応するクラスを指定する必要があります。
<bean class="com.test.bean.Student"/>
クラスの横に Bean アイコンが表示され、Bean が正常に登録されたことがわかります。このようにして、タイプに応じてコンテナに Bean インスタンス オブジェクトを要求できます。
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
//getBean有多种形式,其中第一种就是根据类型获取对应的Bean
//容器中只要注册了对应类的Bean或是对应类型子类的Bean,都可以获取到
Student student = context.getBean(Student.class);
student.hello();
}
ただし、場合によっては Bean の取得があいまいになることがあるため、2 つのサブクラスの Bean を個別に登録できます。
public class ArtStudent extends Student{
public void art(){
System.out.println("我爱画画");
}
}
public class SportStudent extends Student{
public void sport(){
System.out.println("我爱运动");
}
}
<bean class="com.test.bean.ArtStudent"/>
<bean class="com.test.bean.SportStudent"/>
ただし、現時点では Bean を取得するときに、その親クラスを要求します。
Student student = context.getBean(Student.class);
student.hello();
実行中に次のエラーが表示されます。
Bean 定義が一意ではないという例外があります。明らかに、必要なタイプは Student ですが、このタイプを満たす Bean 定義が 2 つあります。どちらも Student のサブクラスです。現時点では、IoC コンテナは何を認識していませんどの Bean が返されるかが返されるため、例外をスローすることしかできません。
したがって、Bean が必要で、型を使用してそれを取得する場合は、型を指定する必要があり、あいまいさがあってはなりません。
ArtStudent student = context.getBean(ArtStudent.class);
student.art();
2 つの Bean タイプが同じ場合はどうなるでしょうか?
<bean class="com.test.bean.Student"/>
<bean class="com.test.bean.Student"/>
この場合、Class を使用して区別することはできませんが、Bean の対応する型を指定することに加えて、区別するために Bean の名前を指定することもできます。
<bean name="art" class="com.test.bean.ArtStudent"/>
<bean name="sport" class="com.test.bean.SportStudent"/>
name 属性は、この Bean に一意の名前を設定します (name と同じ機能を持つ id 属性も使用できますが、名前が統一されているかどうかをチェックし、統一されていない場合は黄色のマークが表示されます)。同じ名前を使用することはできません。同じ名前を使用しないと、エラーが報告されます。
<bean name="a" class="com.test.bean.Student"/>
<bean name="b" class="com.test.bean.Student"/>
このようにして、これら 2 つの Bean を区別できます。
Student student = (Student) context.getBean("a");
student.hello();
現在の 2 つの Bean 定義はまったく同じで違いはありませんが、実際には同じタイプの 2 つの異なる Bean であり、後でこれら 2 つの Bean に異なる他のプロパティを設定することもできます。
Bean に名前またはエイリアスを付けることができます。名前に加えて、独自のニックネームを付けることもできます。
<bean name="a" class="com.test.bean.Student"/>
<alias name="a" alias="test"/>
このようにして、エイリアスを使用して対応する Bean を取得することもできます。
Student student = (Student) context.getBean("test");
student.hello();
IoC コンテナによって作成される Bean は 1 つだけですか、それとも、要求するたびに新しいオブジェクトが提供されるのでしょうか? ここで、main メソッドで Bean オブジェクトを 2 回続けて取得します。
Student student1 = context.getBean(Student.class);
Student student2 = context.getBean(Student.class);
System.out.println(student1 == student2); //默认为单例模式,对象始终为同一个
最終結果は true であることがわかりました。これは、IoC コンテナから取得されるオブジェクトが常に同じであることを意味します。デフォルトでは、IoC コンテナを通じて管理される Bean はシングルトン モードです。このオブジェクトは 1 回だけ作成されます。
毎回取得するオブジェクトを新しいものにしたい場合は、そのスコープを変更することもできます。
ここには 2 種類のスコープがあります. 1 つはsingleton
デフォルトでこれです. もちろんprototype
プロトタイプ モードもあります (便宜的にマルチ インスタンス モードとも呼ばれます). このモードは毎回オブジェクトを取得します. new:
Student student1 = context.getBean(Student.class); //原型模式下,对象不再始终是同一个了
Student student2 = context.getBean(Student.class);
System.out.println(student1 == student2);
実際、Bean のスコープがシングルトン モードの場合、Bean は最初 (コンテナーが設定をロードするとき) に作成され、後で取得するのはこのオブジェクトだけです。プロトタイプモードでは取得時にのみ作成される、つまりシングルトンモードではIoCコンテナにBeanが格納され、コンテナが破壊されない限りオブジェクトは常に存在し、プロトタイプはオブジェクトを使用したいときに直接新規作成すると保存されないため、このモードは非常に便利です。
もちろん、シングルトン モードの Bean を最初にロードせず、必要に応じて再度ロードしたい場合は (ロード後もコンテナによって格納され、このオブジェクトは今後も使用されます)新しいものが作成されます) 遅延読み込みを有効にすることもできます。
<bean class="com.test.bean.Student" lazy-init="true"/>
遅延読み込みをオンにすると、オブジェクトは実際に初めて使用されるときにのみ作成されます。
Bean は IoC コンテナーによってシングルトン モードでロードされますが、ロード順序がわからないため、Bean のロード順序を維持する必要がある場合 (たとえば、Bean を別の Bean の前に作成する必要がある場合)、次のように使用できますdepends-on
。依存する Bean が前にロードされるように、ロードされる Bean を設定します。たとえば、Teacher は Student の前にロードされる必要があります。
<bean name="teacher" class="com.test.bean.Teacher"/>
<bean name="student" class="com.test.bean.Student" depends-on="teacher"/>
これにより、Bean のロード順序が保証されます。
依存性注入
依存性注入 (DI) は設計パターンであり、Spring フレームワークの中核概念の 1 つです。Bean の登録方法と使用方法は理解できましたが、これだけでは十分ではありません。最初にクラス間の強い関連性を排除したことを覚えていますか? たとえば、教師用インターフェイスが追加されました。
public interface Teacher {
void teach();
}
具体的な実装は 2 つあります。
public class ArtTeacher implements Teacher{
@Override
public void teach() {
System.out.println("我是美术老师,我教你画画!");
}
}
public class ProgramTeacher implements Teacher{
@Override
public void teach() {
System.out.println("我是编程老师,我教你学Golang!");
}
}
私たちの生徒にはまず、美術の先生など、次のことを教えてもらう先生がいます。
public class Student {
private Teacher teacher = new ArtTeacher();
//在以前,如果我们需要制定哪个老师教我们,直接new创建对应的对象就可以了
public void study(){
teacher.teach();
}
}
しかし、美術教師が教えなくなり、別の教師が生徒を教えるようになった場合は、Student クラスの定義を変更する必要があることがわかりました。
public class Student {
private Teacher teacher = new ProgramTeacher();
...
現在、さまざまなクラスが出現し、このように Teacher を使用する必要がある場合、Teacher の実装が変更されると、これまで Teacher を使用していたクラスを 1 つずつ変更する必要があり、非常に不快であることが想像できます。
依存関係の注入を使用すると、IoC コンテナーによって Student の Teacher メンバー変数を割り当てて、適切な Teacher オブジェクトを選択できます。つまり、IoC コンテナーがオブジェクトを作成するときに、事前に指定された属性をオブジェクトに注入する必要があります。非常に単純です。タグを使用してproperty
それを実現できます。Bean タグを展開します。
<bean name="teacher" class="com.test.bean.ProgramTeacher"/>
<bean name="student" class="com.test.bean.Student">
<property name="teacher" ref="teacher"/>
</bean>
同時に、Student クラスも変更する必要があります。依存関係の注入では、対応する属性に set メソッドが必要です。
public class Student {
private Teacher teacher;
//要使用依赖注入,我们必须提供一个set方法(无论成员变量的访问权限是什么)命名规则依然是驼峰命名法
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
...
これを使用してproperty
、注入する必要がある値または Bean を指定します。ここでは、ProgramTeacher を選択します。その後、使用すると、Student クラスで取得されるものがこの Bean のオブジェクトになります。
Student student = context.getBean(Student.class);
student.study();
ご覧のとおり、現在の Java コードには、特定の実装クラス情報は表示されません (ArtTeacher と ProgramTeacher は表示されません)。代わりに、大量の XML 設定が存在します。別のクラスの場合、コードを調整する必要はなく、Bean タイプを変更するだけです。
<!-- 只需要修改这里的class即可,现在改为ArtTeacher -->
<bean name="teacher" class="com.test.bean.ArtTeacher"/>
<bean name="student" class="com.test.bean.Student">
<property name="teacher" ref="teacher"/>
</bean>
このようにして、Bean クラスは新しい型になり、他の場所でコードを調整してプログラムを再度開始する必要がなくなります。
依存性注入を通じて、Spring がもたらしてくれる便利さを少しずつ感じ始めたでしょうか。もちろん、依存関係の注入は必ずしも他の Bean を注入する必要はなく、単純な値を使用することもできます。
<bean name="student" class="com.test.bean.Student">
<property name="name" value="卢本伟"/>
</bean>
直接使用では、value
特定の値を直接渡すことができます。
実際、多くの場合、クラス内の一部のパラメーターは、作成後ではなくコンストラクター内で初期化されます。次に例を示します。
public class Student {
private final Teacher teacher; //构造方法中完成,所以说是一个final变量
public Student(Teacher teacher){
//Teacher属性是在构造方法中完成的初始化
this.teacher = teacher;
}
...
前に述べたように、Bean は実際には IoC コンテナによって作成されますが、パラメータのないデフォルトの構造を変更しました。設定ファイルにエラーが報告されていることがわかります。
明らかに、コンストラクターを変更したため、IoC コンテナーはデフォルトでパラメーターなしのコンストラクターのみを呼び出します。したがって、使用可能なコンストラクターを指定する必要があります。Bean ラベルを展開して、ラベルを追加しますconstructor-arg
。
<bean name="teacher" class="com.test.bean.ArtTeacher"/>
<bean name="student" class="com.test.bean.Student">
<constructor-arg name="teacher" ref="teacher"/>
</bean>
ここにあるのはconstructor-arg
構築メソッドのパラメータです。このパラメータには多くのパラメータを記述することができ、内部のパラメータの数に一致する構築メソッドが自動的に一致します。ここで一致するのは、1 つのパラメータを必要とする先ほど書いた構築メソッドです。パラメータ。
このように依存関係注入も実装できますが、今回は依存関係注入のタイミングをオブジェクト構築まで早めます。
これが起こったらどうしますか?Student クラスは次のように定義されています。
public class Student {
private final String name;
public Student(String name){
System.out.println("我是一号构造方法");
this.name = name;
}
public Student(int age){
System.out.println("我是二号构造方法");
this.name = String.valueOf(age);
}
}
この際、2号工法を使用したいのですが、どのように指定すればよいのでしょうか?タグにタイプを追加するには 2 つの方法があります。
<constructor-arg value="1" type="int"/>
対応するパラメータ名として指定することもできます。
<constructor-arg value="1" name="age"/>
とにかく、指定したパラメータがターゲットの構築方法と一致していることを確認できれば大丈夫です。
ここで、コレクション型である特別な型がクラスに表示されます。
public class Student {
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
}
このコレクション タイプには特別なサポートがあります。
<bean name="student" class="com.test.bean.Student">
<!-- 对于集合类型,我们可以直接使用标签编辑集合的默认值 -->
<property name="list">
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
</bean>
List だけでなく、Map や Set などの一般的に使用されるコレクション クラス (配列も含む) もこの方法での書き込みをサポートしています。たとえば、Map 型は以下を使用して注入することもできますentry
。
<bean name="student" class="com.test.bean.Student">
<property name="map">
<map>
<entry key="语文" value="100.0"/>
<entry key="数学" value="80.0"/>
<entry key="英语" value="92.5"/>
</map>
</property>
</bean>
これまでに、次の 2 種類の依存性注入の研究を完了しました。
- Setter 依存関係の注入: メンバー属性に対応する set メソッドを通じて注入が完了します。
- コンストラクターの依存関係の注入: 注入はコンストラクターを通じて完了します。
自動組立
以前は、依存関係の注入を使用する必要がある場合は、property
パラメーターを構成する必要がありました。
<bean name="student" class="com.test.bean.Student">
<property name="teacher" ref="teacher"/>
</bean>
ただし、便宜上、自動アセンブリを有効にすることもできます。オートワイヤーとは、IoC コンテナーに入力する必要のある値を見つけさせることです。必要なのは set メソッドを提供することだけです。ここでは autowire 属性を追加する必要があります。
<bean name="student" class="com.test.bean.Student" autowire="byType"/>
autowire
この属性には共通の値が 2 つあり、1 つは byName 、もう 1 つは byType で、その名前が示すように、1 つは型に基づいて自動アセンブリに適切な Bean を検索するためのもので、もう 1 つは名前に基づいて検索するためのものです。明示的に指定する必要はありませんproperty
。
このとき、設定されたメソッドの横に自動アセンブリアイコンが表示され、その効果は上記と同じです。
コンストラクター メソッドを使用して依存関係の注入を完了する場合、自動アセンブリもサポートされており、autowire を次のように変更するだけで済みます。
<bean name="student" class="com.test.bean.Student" autowire="constructor"/>
この方法では、対応するパラメーターを持つコンストラクターを提供するだけで済みます (この場合、byType もデフォルトでそれを探します)。
これにより、自動注入も完了できます。
自動化するとトラブルは軽減されますが、機械的すぎるため、自動組み立てでは次のような問題が発生する場合があります。
この時点では、autowire
ルールが byType であるため、候補 Bean が 2 つありますが、実際には、ProgramTeacher Bean がいかなる状況でも自動アセンブリに参加しないことを望んでいます。この時点で、その自動アセンブリ候補をオフにすることができます。
<bean name="teacher" class="com.test.bean.ArtTeacher"/>
<bean name="teacher2" class="com.test.bean.ProgramTeacher" autowire-candidate="false"/>
<bean name="student" class="com.test.bean.Student" autowire="byType"/>
falseを設定した場合autowire-candidate
、このBeanは自動アセンブルの候補Beanから外れ、自動アセンブル対象となる一意のBeanは1つだけとなり、エラーは解消され、プログラムが正常に実行できるようになります。
このメソッドに加えて、この Bean がメイン Bean であることを示すために、primary 属性を設定することもできます。あいまいさが発生した場合は、それが最初に選択されます。
<bean name="teacher" class="com.test.bean.ArtTeacher" primary="true"/>
<bean name="teacher2" class="com.test.bean.ProgramTeacher"/>
<bean name="student" class="com.test.bean.Student" autowire="byType"/>
このように書かれたプログラムは正常に実行でき、ArtTeacher が選択されています (なぜ IDEA に赤いマークが付いているのかわかりませんが、バグ?)
ライフサイクルと継承
コンストラクター メソッドの変更に加えて、オブジェクトの作成時と破棄時に他のタスクを実行するために Bean の初期化メソッドと破棄メソッドを指定することもできます。
public void init(){
System.out.println("我是对象初始化时要做的事情!");
}
public void destroy(){
System.out.println("我是对象销毁时要做的事情!");
}
init-method
とでdestroy-method
指定できます。
<bean name="student" class="com.test.bean.Student" init-method="init" destroy-method="destroy"/>
それでは、いつ初期化され、いつ破棄されるのでしょうか?
//当容器创建时,默认情况下Bean都是单例的,那么都会在一开始就加载好,对象构造完成后,会执行init-method
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
//我们可以调用close方法关闭容器,此时容器内存放的Bean也会被一起销毁,会执行destroy-method
context.close();
したがって、最終的な結果は次のようになります。
Bean がシングルトン モードではなくプロトタイプ モードである場合、Bean は取得時にのみ作成され、init メソッドが呼び出され、対応する破棄メソッドは呼び出されないことに注意してください (したがって、Bean の場合、プロトタイプモードでは、Spring は完全なライフサイクルを考慮することができません。シングルトンモードでは、Bean オブジェクトの作成からオブジェクトの破棄まで Spring が管理できます) 公式ドキュメントの原文は次のとおりです。
他のスコープとは対照的に、Spring はプロトタイプ Bean の完全なライフサイクルを管理しません。コンテナーは、プロトタイプ オブジェクトをインスタンス化し、構成し、その他の方法で組み立ててクライアントに渡しますが、そのプロトタイプ インスタンスのそれ以上の記録はありません。したがって、初期化ライフサイクル コールバック メソッドはスコープに関係なくすべてのオブジェクトで呼び出されますが、プロトタイプの場合、構成された破棄ライフサイクル コールバックは呼び出されません。クライアント コードは、プロトタイプ スコープのオブジェクトをクリーンアップし、プロトタイプ Bean が保持している高価なリソースを解放する必要があります。Spring コンテナがプロトタイプ スコープの Bean によって保持されているリソースを解放できるようにするには、クリーンアップする必要がある Bean への参照を保持するカスタムBean ポストプロセッサを使用してみてください。
Bean にも継承関係がありますが、ここでの継承はクラスの継承ではなく、次のような属性の継承です。
public class SportStudent {
private String name;
public void setName(String name) {
this.name = name;
}
}
public class ArtStudent {
private String name;
public void setName(String name) {
this.name = name;
}
}
この時点で、まず ArtStudent を Bean として登録します。
<bean name="artStudent" class="com.test.bean.ArtStudent">
<property name="name" value="小明"/>
</bean>
ここでは、name の初期値を注入します。この時点で、SportStudent Bean を作成しました。この Bean のプロパティが、先ほど作成した Bean のプロパティと同じであることを望みます。その後、同じものを作成できます。
<bean class="com.test.bean.SportStudent">
<property name="name" value="小明"/>
</bean>
でも属性が多すぎると書くのがちょっと面倒になるかな?この場合、Bean 間の継承関係を構成でき、ArtStudent Bean によって構成されたプロパティを SportStudent Bean に直接継承させることができます。
<bean class="com.test.bean.SportStudent" parent="artStudent"/>
このようにして、ArtStudent Bean で設定されたプロパティは SportStudent Bean に直接継承されます (設定されたすべてのプロパティはサブ Bean にも存在し、注入できる必要があることに注意してください。そうでない場合はエラーが発生します)。サブクラス内 一部のプロパティは特別であり、継承に基づいて個別に構成することもできます。
<bean name="artStudent" class="com.test.bean.ArtStudent" abstract="true">
<property name="name" value="小明"/>
<property name="id" value="1"/>
</bean>
<bean class="com.test.bean.SportStudent" parent="artStudent">
<property name="id" value="2"/>
</bean>
特定の Bean を、他の Bean が継承して使用するための構成テンプレートとしてのみ使用したい場合は、コンテナがこの Bean のオブジェクトを作成しないように、それを抽象として構成できます。
<bean name="artStudent" class="com.test.bean.ArtStudent" abstract="true">
<property name="name" value="小明"/>
</bean>
<bean class="com.test.bean.SportStudent" parent="artStudent"/>
抽象 Bean として宣言されると、そのインスタンス化されたオブジェクトはコンテナを通じて取得できないことに注意してください。
ただし、Bean継承の使用頻度はそれほど高くないので、使いこなしておきましょう。
最後に、さまざまな Bean 構成プロパティについてすでに学習しましたが、コンテキスト全体のすべての Bean に特定の構成を採用させたい場合は、最も外側の Bean タグでデフォルト構成を作成できます。
このように、Bean に特定の属性が設定されていない場合でも、最外層にデフォルト設定が記述されていれば、Bean 自体がデフォルト設定をオーバーライドする設定をしない限り、その属性が有効になります。
ファクトリ パターンとファクトリ Bean
前に、IoC コンテナの Bean 作成メカニズムを紹介しました。デフォルトでは、コンテナは、オブジェクトを作成するために、対応するタイプの Bean のコンストラクタを呼び出します。ただし、場合によっては、外部の世界に Bean のコンストラクタを使用させたくない場合があります。ファクトリ メソッドのデザイン パターン (詳細については、ビデオ チュートリアル「Java デザイン パターン」をご覧ください) では、Spring が構築メソッドを通じて Bean オブジェクトを作成するためにリフレクション メカニズムを直接使用しないことを推奨します。ただし、リフレクション メカニズムを使用して、まず対応するファクトリ クラスを見つけてから、そのファクトリ クラスを使用して必要な Bean オブジェクトを生成します。
public class Student {
Student() {
System.out.println("我被构造了");
}
}
public class StudentFactory {
public static Student getStudent(){
System.out.println("欢迎光临电子厂");
return new Student();
}
}
現時点では、Student にはファクトリがあります。通常、Student オブジェクトを取得するにはファクトリを使用する必要があります。今度は、Spring が同じことを行うことを期待しています。コンストラクタ メソッドを作成するためにリフレクションを直接使用する代わりに、ファクトリを通じてそれを指定できます。方法:
<bean class="com.test.bean.StudentFactory" factory-method="getStudent"/>
なお、ここでのBean型はStudentクラスのファクトリクラスとして入力する必要があり、対応するファクトリメソッドを指定するためにfactory-methodを追加しますが、最後に登録されるのはファクトリメソッドの戻り値の型なので、まだ学生の豆です:
この時点で、再度取得します。取得するものは、ファクトリ メソッドを通じて取得したオブジェクトでもあります。
ここで誤解があります。StudentFactory Bean を登録したとは考えないでください。このクラスは、Spring にファクトリ メソッドの場所を伝えるためだけにこのクラスとして入力されています。実際に登録されるのは、ファクトリ メソッドが提供するものです。
ファクトリモードを採用すると、Bean に対する依存性注入などの操作は設定ファイルから実行できなくなり、ファクトリメソッド内でのみ完了できるようになるのですが、これは Spring の設計思想に反するのではないでしょうか?
もちろん、ファクトリ クラスによっては、使用する前にオブジェクトを構築する必要がある場合もありますが、ファクトリ クラスをファクトリ Bean として直接登録することもできます。
public class StudentFactory {
public Student getStudent(){
System.out.println("欢迎光临电子厂");
return new Student();
}
}
Student を取得するには StudentFactory オブジェクトが必要ですが、現時点では、それを最初に Bean として登録することしかできません。
<bean name="studentFactory" class="com.test.bean.StudentFactory"/>
次のようにファクトリ クラスを Bean として登録します。これをファクトリ Bean と呼び、factory-bean
Bean のファクトリ Bean を指定するために使用します。
<bean factory-bean="studentFactory" factory-method="getStudent"/>
Factory-Bean を使用した後は、クラスを指定する必要がなくなり、クラスを直接使用できることに注意してください。
このとき、ファクトリメソッドにもアイコンが付いていることがわかります このように、ファクトリクラスがBeanとして登録されるので、ファクトリBeanに対する依存性注入などを設定ファイルで設定することができます。
ここにも非常に細かい操作があり、ファクトリー Bean が提供する Bean を取得したい場合は、ファクトリー Bean の名前を直接入力できます。これにより、ファクトリー Bean のインスタンスではなく、Bean のインスタンスが取得されます。ファクトリービーンによって生成される:
Student bean = (Student) context.getBean("studentFactory");
もちろん、ファクトリ クラスのインスタンスを取得する必要がある場合は、名前の前にシンボルを追加できます&
。
StudentFactory bean = (StudentFactory) context.getBean("&studentFactory");
もう一つの細かい点。
アノテーションを使用して開発する
構成ファイルの学習はこれまでにほとんど完了しましたが、構成ファイルを使用して構成するのは少し面倒に感じますよね。プロジェクトが非常に大きい場合、構成ファイル全体が Bean 構成で埋め尽くされ、成長し続けることが想像できますが、構成を省略するより効率的な方法はあるでしょうか? JavaWeb ステージで使用した非常に便利なものを覚えていますか? そうです、注釈です。
これから開発にアノテーションを使用するので、以前の XML 構成ファイルを削除して、アノテーションを使用することがどれほど便利かを確認してみましょう。
ApplicationContext context = new AnnotationConfigApplicationContext();
ここで、アノテーションが付けられ構成されたコンテキスト実装として AnnotationConfigApplicationContext を使用します。
アノテーションを使用するようになったので、クラスを使用して構成ファイルを記述する必要があります。以前は、構成を記述したい場合は次のものが必要でした。
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
ここで必要なのは、構成クラスを作成することだけです。
@Configuration
public class MainConfiguration {
}
同様に、最初に構成コンテキストが存在しないことを示すプロンプトが表示されます。
上記と同様に、ここでも必要に応じて設定するだけです。これは影響するだけです。