3. SpringのIOCコンテナの詳細説明

IoC は、Inversion of Control の略語で、「制御の反転」と訳されます。これはテクノロジーではなく、設計思想です。疎結合とより良いプログラムを設計する方法をガイドできる重要なオブジェクト指向プログラミング規則です。

Spring は、IoC コンテナを通じてすべての Java オブジェクトのインスタンス化と初期化を管理しオブジェクト間の依存関係を制御しますIoC コンテナによって管理される Java オブジェクトを Spring Beanと呼びます。これは、キーワード new を使用して作成される Java オブジェクトとの間に違いはありません。

IoC コンテナは Spring フレームワークの最も重要なコア コンポーネントの 1 つであり、Spring の誕生から成長までの全プロセスを実行します。

1. IoCコンテナ

1.1. 制御の反転 (IoC)

ここに画像の説明を挿入します

  • 制御の反転は思考です。

  • 制御の反転は、プログラムの結合を減らし、プログラムのスケーラビリティを向上させることを目的としています。

  • 制御の反転、反転とは何ですか?

    • オブジェクトの作成権限をサードパーティのコンテナに渡します。
    • オブジェクトの保守権限とオブジェクト間の関係をサードパーティのコンテナに引き渡します。
  • 制御の反転のアイデアをどのように実装するか?

    • DI (Dependency Injection): 依存性注入

1.2. 依存性の注入

DI (Dependency Injection): 依存性注入は制御反転の考え方を実現します。

依存関係の注入:

  • Spring がオブジェクトを作成し、構成を通じてオブジェクトの依存関係プロパティを挿入するプロセスを指します。

依存関係の注入には、次の 2 つの一般的な実装方法があります。

  • 最初のタイプ: セット注入
  • 2 番目のタイプ: コンストラクター インジェクション

結論としては、IOC は制御の反転のアイデアであり、DI は IoC の具体的な実装です。

Bean 管理では、Bean オブジェクトの作成と Bean オブジェクト内のプロパティの割り当て (または Bean オブジェクト間の関係の維持) について説明します。

1.3. SpringでのIoCコンテナの実装

Spring の IoC コンテナは、IoC の考え方を実用的な製品に実装したものです。IoCコンテナで管理されるコンポーネントはBeanとも呼ばれます。Bean を作成する前に、まず IoC コンテナを作成する必要があります。Spring は、IoC コンテナの 2 つの実装を提供します。

①ビーンファクトリー

これは IoC コンテナの基本的な実装であり、Spring によって内部的に使用されるインターフェイスです。開発者のためではなく、Spring 自体のためです。

②アプリケーションコンテキスト

より高度な機能を提供する BeanFactory のサブインターフェース。Spring ユーザーの場合、ほとんどすべての状況で、基盤となる BeanFactory の代わりに ApplicationContext が使用されます。

③ApplicationContextのメイン実装クラス

画像

型名 導入
ClassPathXmlApplicationContext クラスパスの下にあるXML形式の構成ファイルを読み取って、IOCコンテナオブジェクトを作成します。
FileSystemXmlApplicationContext ファイル システム パスを介して XML 形式の構成ファイルを読み取り、IOC コンテナ オブジェクトを作成します。
構成可能なアプリケーションコンテキスト ApplicationContext のサブインターフェイスには、いくつかの拡張メソッド Refresh() および close() が含まれており、これにより ApplicationContext はコンテキストを開始、閉じ、更新することができます。
Webアプリケーションコンテキスト Web アプリケーション用に特別に準備され、Web 環境に基づいて IOC コンテナ オブジェクトを作成し、そのオブジェクトを ServletContext ドメインにインポートして保存します。

2. XMLによるBean管理

2.1 サブモジュール spring6-ioc-xml をビルドする

①モジュールの構築

施工方法はスプリングファーストです。

②設定ファイルの導入

Spring-First モジュール構成ファイルの導入:Beans.xml、log4j2.xml

③依存関係を追加する

<dependencies>
        <!--spring context依赖-->
        <!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.11</version>
        </dependency>

        <!--junit5测试-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.9.2</version>
        </dependency>

        <!--log4j2的依赖-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.20.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j2-impl</artifactId>
            <version>2.20.0</version>
        </dependency>
    </dependencies>

④Javaクラスの導入

Spring-First モジュールの Java エンティティ クラスを導入する

画像-20230830150556427

2.2 実験 1: Bean を取得する

①方法1:IDから取得

id 属性は Bean の一意の識別子を指定するため、Bean タグの id 属性に基づいてコンポーネント オブジェクトを正確に取得できます。これは、私たちが春を始めるときによく使っていた方法です。

画像-20230830151840343

②方法2:型から取得する

画像-20230830152134346

③方法3:IDとタイプによる

画像-20230830152342438

④注意事項

typeに基づいて Bean を取得する場合、IOC コンテナ内に指定されたタイプのBean が 1 つだけ存在する必要があります。

IOC コンテナに合計 2 つが設定されている場合:

画像-20230830152900977

次に、型に基づいて Bean を取得します。

画像-20230830153023661

例外がスローされます。

⑤知識を広げる

コンポーネントクラスがインターフェースを実装している場合、インターフェースの型に基づいてBeanを取得できますか?

はい、前提条件は Bean が一意であることです

package com.jie.ioc.service;

/**
 * @Auther: Administrator
 * @Date: 2023/08/30/15:38
 * @Description:
 */
public interface HelloWorldService {
    
    

     void run();

}
package com.jie.ioc.service.impl;

import com.jie.ioc.HelloWorldTest;
import com.jie.ioc.service.HelloWorldService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author JIE
 * @version 1.0
 * @description: TODO
 * @date 2023/8/30 15:39
 */
public class HelloWorldServiceImpl implements HelloWorldService {
    
    

    private final Logger logger = LoggerFactory.getLogger(HelloWorldTest.class);

    @Override
    public void run() {
    
    
        logger.info("方法调用");
    }
}

画像-20230830154346906

試験結果:

画像-20230830154942040

インターフェースに複数の実装クラスがあり、これらの実装クラスが Bean で構成されている場合、インターフェースのタイプに基づいて Bean を取得できますか?

いいえ、Bean は一意ではないため、

package com.jie.ioc.service.impl;

import com.jie.ioc.HelloWorldTest;
import com.jie.ioc.service.HelloWorldService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author JIE
 * @version 1.0
 * @description: 第二个实现类
 * @date 2023/8/30 15:39
 */
public class HelloWorldServiceImpl2 implements HelloWorldService {
    
    

    private final Logger logger = LoggerFactory.getLogger(HelloWorldTest.class);

    @Override
    public void run() {
    
    
        logger.info("方法调用");
    }
}

画像-20230830155137074

試験結果:

画像-20230830155214596

結論は

Beanを型に基づいて取得する場合、Beanの一意性を満たすことを前提として、実際には「オブジェクトinstanceofで指定された型」の戻り結果のみに依存します。戻り値がtrueであれば取得可能です。タイプと一致するとみなされるため、取得できます。

Java では、instanceof 演算子は、前のオブジェクトが後続のクラスのインスタンスであるか、そのサブクラスまたは実装クラスであるかを判断するために使用されます。存在する場合は true を返し、そうでない場合は false を返します。つまり、instanceof キーワードを使用して判断を行う場合、instanceof 演算子の左右の操作には継承または実装の関係がなければなりません。

2.3 実験 2: 依存性注入セッター注入

①学生クラスを作成する Student

package com.jie.ioc.model;

public class Student {
    
    

    private Integer id;

    private String name;

    private Integer age;

    private String sex;

    public Student() {
    
    
    }

    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;
    }

    public Integer getAge() {
    
    
        return age;
    }

    public void setAge(Integer age) {
    
    
        this.age = age;
    }

    public String getSex() {
    
    
        return sex;
    }

    public void setSex(String sex) {
    
    
        this.sex = sex;
    }

    @Override
    public String toString() {
    
    
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }

}

②Bean設定時にプロパティに値を代入する

<bean id="studentOne" class="com.jie.ioc.model.Student">
    <!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
    <!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关) -->
    <!-- value属性:指定属性值 -->
    <property name="id" value="1001"/>
    <property name="name" value="张三"/>
    <property name="age" value="23"/>
    <property name="sex" value=""/>
</bean>

③テスト

@Test
public void testDIBySet(){
    
    
    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
    Student studentOne = ac.getBean("studentOne", Student.class);
    System.out.println(studentOne);
}

画像-20230830164909282

2.4 実験 3: 依存性注入のコンストラクター注入

①Studentクラスにパラメータ化された構成要素を追加します。

public Student(Integer id, String name, Integer age, String sex) {
    
    
    this.id = id;
    this.name = name;
    this.age = age;
    this.sex = sex;
}

②Beanの設定

spring-di.xml

  <bean id="studentTwo" class="com.jie.ioc.model.Student">
        <constructor-arg value="1002"/>
        <constructor-arg value="李四"/>
        <constructor-arg value="33"/>
        <constructor-arg value=""/>
    </bean>

知らせ:

constructor-arg タグには、コンストラクターのパラメーターをさらに説明する 2 つの属性もあります。

  • Index 属性: パラメータの位置のインデックスを指定します (0 から始まります)。
  • name 属性: パラメータ名を指定します

③テスト

@Test
public void testDIByConstructor(){
    
    
    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
    Student studentOne = ac.getBean("studentTwo", Student.class);
    System.out.println(studentOne);
}

画像-20230830165839973

2.5 実験 4: 特殊な値の処理

①リテラル代入

リテラルとは何ですか?

int a = 10;

変数 a を宣言し、10 に初期化します。このとき、a は文字 a を表すのではなく、変数 の名前になりますa を参照すると、実際には値 10 が得られます。

そして、a が引用符で囲まれている場合: 'a' は、変数ではなく、リテラルである文字 a 自体を表します。したがって、リテラル値には拡張的な意味はなく、私たちが目にするデータそのものです。

<!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 -->
<property name="name" value="张三"/>

②null値

<property name="name">
    <null />
</property>

知らせ:

<property name="name" value="null"></property>

上記の書き方ではnameに代入する値は文字列nullとなっています。

③xmlエンティティ

<!-- 小于号在XML文档中用来定义标签的开始,不能随便使用 -->
<!-- 解决方案一:使用XML实体来代替 -->
<property name="expression" value="a &lt; b"/>

④CDATAセクション

<property name="expression">
    <!-- 解决方案二:使用CDATA节 -->
    <!-- CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据 -->
    <!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析 -->
    <!-- 所以CDATA节中写什么符号都随意 -->
    <value><![CDATA[a < b]]></value>
</property>

2.6. 実験 5: オブジェクト型属性への値の割り当て

①クラスクラスClazzを作成する

package com.jie.ioc.model;
    
public class Clazz {
    
    

    private Integer clazzId;

    private String clazzName;

    public Integer getClazzId() {
    
    
        return clazzId;
    }

    public void setClazzId(Integer clazzId) {
    
    
        this.clazzId = clazzId;
    }

    public String getClazzName() {
    
    
        return clazzName;
    }

    public void setClazzName(String clazzName) {
    
    
        this.clazzName = clazzName;
    }

    @Override
    public String toString() {
    
    
        return "Clazz{" +
                "clazzId=" + clazzId +
                ", clazzName='" + clazzName + '\'' +
                '}';
    }

    public Clazz() {
    
    
    }

    public Clazz(Integer clazzId, String clazzName) {
    
    
        this.clazzId = clazzId;
        this.clazzName = clazzName;
    }
}

②Studentクラスを変更する

Student クラスに次のコードを追加します。

画像-20230831155426370

private Clazz clazz;

public Clazz getClazz() {
    
    
	return clazz;
}

public void setClazz(Clazz clazz) {
    
    
	this.clazz = clazz;
}

方法 1: 外部 Bean を参照する

Clazz タイプ Bean を構成します。

<bean id="clazzOne" class="com.jie.ioc.model.Clazz">
        <property name="clazzId" value="1111"/>
        <property name="clazzName" value="财源滚滚班"/>
</bean>

Student の clazz 属性に値を割り当てます。

画像-20230831155742937

<bean id="studentOne" class="com.jie.ioc.model.Student">
    <!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
    <!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关) -->
    <!-- value属性:指定属性值 -->
    <property name="id" value="1001"/>
    <property name="name" value="null"/>
    <property name="age" value="23"/>
    <property name="sex" value=""/>
    <!-- ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值 -->
    <property name="clazz" ref="clazzOne"/>
</bean>

試験結果:

画像-20230831160029763

toString メソッドを忘れずに再生成してください。

画像-20230831160104016

エラーのデモンストレーション:

画像-20230831160129284

画像-20230831160216242

場合によっては、ref プロパティが写成された value プロパティ、会議が発生します: org.springframework.beans.factory.BeanCreationException: クラス パス リソース [bean.xml] で定義された名前 'studentOne' を持つ Bean の作成中にエラーが発生しました: のプロパティ値を変換できませんでしたプロパティ「clazz」の必須タイプ「com.jie.ioc.model.Clazz」に「java.lang.String」を入力します。タイプ「java.lang.String」の値を、プロパティ「clazz」に必要なタイプ「com.jie.ioc.model.Clazz」に変換できません: 一致するエディターまたは変換戦略が見つかりません。

これは、String 型を必要な Clazz 型に変換できないことを意味します。これは、value 属性を使用するとき、Spring はこの属性を通常の文字列としてのみみなし、Bean ID であるとはみなさず、使用することはおろか、考慮しないことを意味します。 . 値を割り当てる Bean を検索します。

方法 2: 内部 Bean

画像-20230831160757368

<bean id="studentOne" class="com.jie.ioc.model.Student">
    <!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
    <!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关) -->
    <!-- value属性:指定属性值 -->
    <property name="id" value="1001"/>
    <property name="name" value="null"/>
    <property name="age" value="23"/>
    <property name="sex" value=""/>
    <property name="clazz">
        <!-- 在一个bean中再声明一个bean就是内部bean -->
        <!-- 内部bean只能用于给属性赋值,不能在外部通过IOC容器获取,因此可以省略id属性 -->
        <bean class="com.jie.ioc.model.Clazz">
            <property name="clazzId" value="2222"/>
            <property name="clazzName" value="远大前程班"/>
        </bean>
    </property>
</bean>

試験結果:
画像-20230831160827067

方法 3: カスケード属性の割り当て

画像-20230831160933610

<bean id="studentOne" class="com.jie.ioc.model.Student">
    <!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
    <!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关) -->
    <!-- value属性:指定属性值 -->
    <property name="id" value="1001"/>
    <property name="name" value="null"/>
    <property name="age" value="23"/>
    <property name="sex" value=""/>
    <property name="clazz" ref="clazzOne"/>
    <property name="clazz.clazzId" value="3333"/>
    <property name="clazz.clazzName" value="最强王者班"/>
</bean>

試験結果:

画像-20230831160952893

2.7 実験6: 配列型属性への値の代入

①Studentクラスを変更する

Student クラスに次のコードを追加します。

画像-20230831164250838

private String[] hobbies;

public String[] getHobbies() {
    
    
    return hobbies;
}

public void setHobbies(String[] hobbies) {
    
    
    this.hobbies = hobbies;
}

②Beanの設定

画像-20230831164348262

<bean id="studentOne" class="com.jie.ioc.model.Student">
    <!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
    <!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关) -->
    <!-- value属性:指定属性值 -->
    <property name="id" value="1001"/>
    <property name="name" value="null"/>
    <property name="age" value="23"/>
    <property name="sex" value=""/>
    <property name="clazz" ref="clazzOne"/>
    <property name="clazz.clazzId" value="3333"/>
    <property name="clazz.clazzName" value="最强王者班"/>
    <property name="hobbies">
        <array>
            <value>抽烟</value>
            <value>喝酒</value>
            <value>烫头</value>
        </array>
    </property>
</bean>

試験結果:

toString に変更することを忘れないでください。

画像-20230831164449756

2.8 実験 7: コレクション型属性への値の割り当て

①リストコレクション型の属性に値を代入する

Clazz クラスに次のコードを追加します。

画像-20230831164934375

private List<Student> students;

public List<Student> getStudents() {
    
    
    return students;
}

public void setStudents(List<Student> students) {
    
    
    this.students = students;
}

Bean を構成します。

画像-20230831165506706

 <bean id="clazzOne" class="com.jie.ioc.model.Clazz">
        <property name="clazzId" value="1111"/>
        <property name="clazzName" value="财源滚滚班"/>
        <property name="students">
            <list>
                <ref bean="studentTwo"/>
                <ref bean="studentOne"/>
            </list>
        </property>
    </bean>

試験結果:
画像-20230831165754727

Set コレクション タイプ属性に値を割り当てる場合は、list タグを set タグに変更するだけで済みます。

②Mapコレクションタイプの属性に値を代入する

教師クラスを作成します。 教師:

package com.atguigu.spring6.bean;
public class Teacher {
    
    

    private Integer teacherId;

    private String teacherName;

    public Integer getTeacherId() {
    
    
        return teacherId;
    }

    public void setTeacherId(Integer teacherId) {
    
    
        this.teacherId = teacherId;
    }

    public String getTeacherName() {
    
    
        return teacherName;
    }

    public void setTeacherName(String teacherName) {
    
    
        this.teacherName = teacherName;
    }

    public Teacher(Integer teacherId, String teacherName) {
    
    
        this.teacherId = teacherId;
        this.teacherName = teacherName;
    }

    public Teacher() {
    
    

    }
    
    @Override
    public String toString() {
    
    
        return "Teacher{" +
                "teacherId=" + teacherId +
                ", teacherName='" + teacherName + '\'' +
                '}';
    }
}

Student クラスに次のコードを追加します。

画像-20230831170216337

private Map<String, Teacher> teacherMap;

public Map<String, Teacher> getTeacherMap() {
    
    
    return teacherMap;
}

public void setTeacherMap(Map<String, Teacher> teacherMap) {
    
    
    this.teacherMap = teacherMap;
}

Bean を構成します。

<bean id="teacherOne" class="com.jie.ioc.model.Teacher">
    <property name="teacherId" value="10010"/>
    <property name="teacherName" value="大宝"/>
</bean>

<bean id="teacherTwo" class="com.jie.ioc.model.Teacher">
    <property name="teacherId" value="10086"/>
    <property name="teacherName" value="二宝"/>
</bean>

<bean id="studentOne" class="com.jie.ioc.model.Student">
    <!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
    <!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关) -->
    <!-- value属性:指定属性值 -->
    <property name="id" value="1001"/>
    <property name="name" value="null"/>
    <property name="age" value="23"/>
    <property name="sex" value=""/>
    <property name="hobbies">
        <array>
            <value>抽烟</value>
            <value>喝酒</value>
            <value>烫头</value>
        </array>
    </property>
    <property name="teacherMap">
        <map>
            <entry key="10010" value-ref="teacherOne"/>
            <entry key="10086" value-ref="teacherTwo"/>
        </map>
    </property>
</bean>

試験結果:
画像-20230831170628706

③コレクション型の参照Bean

util:list タグと util:map タグを使用したい場合は、対応する名前空間を導入する必要があります。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

画像-20230831172748169

<!--list集合类型的bean-->
<util:list id="students">
    <ref bean="studentOne"/>
    <ref bean="studentTwo"/>
</util:list>
<!--map集合类型的bean-->
<util:map id="teacherMap">
    <entry key="10010" value-ref="teacherOne"/>
    <entry key="10086" value-ref="teacherTwo"/>
</util:map>

<bean id="studentOne" class="com.jie.ioc.model.Student">
    <!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
    <!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关) -->
    <!-- value属性:指定属性值 -->
    <property name="id" value="1001"/>
    <property name="name" value="null"/>
    <property name="age" value="23"/>
    <property name="sex" value=""/>
    <property name="hobbies">
        <array>
            <value>抽烟</value>
            <value>喝酒</value>
            <value>烫头</value>
        </array>
    </property>
    <property name="teacherMap" ref="teacherMap"/>
</bean>

<bean id="clazzOne" class="com.jie.ioc.model.Clazz">
    <property name="clazzId" value="1111"/>
    <property name="clazzName" value="财源滚滚班"/>
    <property name="students" ref="students"/>
</bean>

試験結果:

画像-20230831172937130

画像-20230831173000252

2.9 実験 8: p 名前空間

まず、名前空間、つまり名前空間とは何かについて説明します。

「実験 7: コレクション タイプのプロパティへの値の割り当て」でコレクション タイプを参照する Bean のデモンストレーション中に注意してください。私たちは追加しました

画像-20230903125625404

この部分、その名前は util です。ここにもう 1 つ追加します。

画像-20230903125807118

たとえば、今私が xmlns を書いているのを見て、このタグ内の属性名がすべて xmlns と呼ばれているかどうかに注目してください。でも、今このように書くのは絶対に間違っています!

同じ名前のプロパティを 2 つ持つことはできないため、セクションを追加できます。

画像-20230903130133496

たとえば、P を追加すると名前空間と呼ばれます。タグ内の属性定義の衝突を避けるためだと簡単に理解できます。次に、そのようなアドレスをその後に追加し、完了後にそれを使用して注入プロセスを完了します。

画像-20230903130240681

完成したら、この効果を試すために簡単なテストを行ってみましょう。

画像-20230903130533779

2.10 実験 9: 外部プロパティ ファイルの導入

次に、外部プロパティ ファイルを導入する方法を学習します。

まず、外部プロパティ ファイルを導入するための要件、またはその適用シナリオについて説明します。皆さん、私はさまざまな属性の注入をすべてほぼ同じファイルに記述していることに注意してください。

画像-20230903135305522

たとえ 1 つの Bean しか注入されていないとしても、それは問題ではありません。しかし、多くの場合、豆は 1 つだけというわけにはいきません。

この時点で、ここにはたくさんの豆があり、それらの多くは注入する価値があることに誰もが気づきました。そうなるとまた修正してメンテナンスしなければならないのですが、特に不便ではないでしょうか?

したがって、実際には通常これを行い、いくつかの特定の固定値を外部ファイルに入れてから、その外部ファイルを導入して内部に注入します。

より一般的なのはデータベース構成です。たとえば、当社のデータには、ユーザー名、パスワード、住所、その他の情報が含まれています。次に、外部ファイルを作成し、そのファイルをインポートして、そのファイルに注入しましょう。これにより、メンテナンスが容易になります。今すぐデータベースを変更したい場合は、外部ファイルを変更しましょう。Spring に挿入されたファイルに関しては、変更する必要はありませんが、これは Spring の基本的な要件の 1 つです。

次に実装を行っていきます。

①依存関係を追加する

<!-- MySQL驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.33</version>
</dependency>

<!-- 数据源 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.16</version>
</dependency>

②外部プロパティファイルの作成

画像-20230903140352553

jdbc.user=root
jdbc.password=ajie
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver

③プロパティファイルの導入

コンテキスト名前空間の導入

画像-20230903140534968

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

</beans>

画像-20230903140702338

<!-- 引入外部属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>

注: context:property-placeholder 要素を使用してアウトソーシング構成ファイル関数をロードする前に、まず XML 構成の第 1 レベルのタグにコンテキスト関連の制約を追加する必要があります。

④Beanの設定

画像-20230903142005151

<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="url" value="${jdbc.url}"/>
    <property name="driverClassName" value="${jdbc.driver}"/>
    <property name="username" value="${jdbc.user}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

⑤テスト

画像-20230903142910352

@Test
public void testDataSource() throws SQLException {
    
    
    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.jdbc.xml");
    DataSource dataSource = ac.getBean(DataSource.class);
    DruidDataSource bean = ac.getBean(DruidDataSource.class);
    System.out.println(bean.getUrl());
    Connection connection = dataSource.getConnection();
    System.out.println(connection);
}

2.11 実験 10: Bean スコープ

①コンセプト

Spring では、Bean タグのscope属性を設定することで Bean のスコープを指定できます。各値の意味を次の表に示します。

価値 意味 オブジェクトを作成する場合
シングルトン (デフォルト) IOC コンテナでは、この Bean のオブジェクトは常に単一のインスタンスです IOCコンテナが初期化されるとき
プロトタイプ この Bean には IOC コンテナ内に複数のインスタンスがあります 豆を手に入れるとき

WebApplicationContext 環境にある場合は、他にもいくつかのスコープがあります (ただし、一般的には使用されません)。

価値 意味
リクエスト リクエストスコープ内で有効
セッション セッションスコープ内で有効

②クラスユーザーの作成

package com.jie.ioc.model;

/**
 * 用户实体类
 *
 * @author 阿杰 [email protected]
 * @version 1.0
 * @date 2023/9/3 14:33
 */
public class User {
    
    

    private Integer id;

    private String username;

    private String password;

    private Integer age;

    public User() {
    
    
    }

    public User(Integer id, String username, String password, Integer age) {
    
    
        this.id = id;
        this.username = username;
        this.password = password;
        this.age = age;
    }

    public Integer getId() {
    
    
        return id;
    }

    public void setId(Integer id) {
    
    
        this.id = id;
    }

    public String getUsername() {
    
    
        return username;
    }

    public void setUsername(String username) {
    
    
        this.username = username;
    }

    public String getPassword() {
    
    
        return password;
    }

    public void setPassword(String password) {
    
    
        this.password = password;
    }

    public Integer getAge() {
    
    
        return age;
    }

    public void setAge(Integer age) {
    
    
        this.age = age;
    }

    @Override
    public String toString() {
    
    
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                '}';
    }
}

③Beanの設定

画像-20230903143843157

<?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.xsd">

    <!-- scope属性:取值singleton(默认值),bean在IOC容器中只有一个实例,IOC容器初始化时创建对象 -->
    <!-- scope属性:取值prototype,bean在IOC容器中可以有多个实例,getBean()时创建对象 -->
    <bean id="user" class="com.jie.ioc.model.User" scope="prototype"/>

</beans>

④テスト

画像-20230903144132045

これはマルチインスタンス モードです。2 つの異なるオブジェクトが作成されます。単一インスタンスで試してみましょう。

画像-20230903144439292

画像-20230903144454878

@Test
public void testBeanScope(){
    
    
    ApplicationContext ac = new ClassPathXmlApplicationContext("spring-scope.xml");
    User user1 = ac.getBean(User.class);
    User user2 = ac.getBean(User.class);
    System.out.println(user1==user2);
}

2.12 実験 11: Bean のライフサイクル

ライフサイクルとは何ですか? 人のライフサイクルと言えば、生まれてから死ぬまでのプロセスです。ここでBeanのライフサイクルとは、Beanオブジェクトの生成から破棄までのプロセスを指し、これをライフサイクルと呼びます。

①特定のBeanのライフサイクルプロセス

  • Beanオブジェクトの作成(パラメータなしのコンストラクタの呼び出し)

  • Bean オブジェクトのプロパティを設定する

  • Bean ポストプロセッサ (初期化前)

  • Bean オブジェクトの初期化 (Bean の構成時に初期化メソッドを指定する必要があります)

  • Bean ポストプロセッサ (初期化後)

  • Bean オブジェクトを使用する準備ができました

  • Bean オブジェクトの破棄 (Bean の構成時に破棄方法を指定する必要があります)

  • IOCコンテナ閉鎖

②クラスUserの変更

package com.jie.ioc.model;

/**
 * 用户实体类
 *
 * @author 阿杰 [email protected]
 * @version 1.0
 * @date 2023/9/3 14:33
 */
public class User {
    
    

    private Integer id;

    private String username;

    private String password;

    private Integer age;

    public User() {
    
    
        System.out.println("生命周期:1、创建对象");
    }

    public User(Integer id, String username, String password, Integer age) {
    
    
        this.id = id;
        this.username = username;
        this.password = password;
        this.age = age;
    }

    public Integer getId() {
    
    
        return id;
    }

    public void setId(Integer id) {
    
    
        System.out.println("生命周期:2、依赖注入");
        this.id = id;
    }

    public String getUsername() {
    
    
        return username;
    }

    public void setUsername(String username) {
    
    
        this.username = username;
    }

    public String getPassword() {
    
    
        return password;
    }

    public void setPassword(String password) {
    
    
        this.password = password;
    }

    public Integer getAge() {
    
    
        return age;
    }

    public void setAge(Integer age) {
    
    
        this.age = age;
    }

    public void initMethod(){
    
    
        System.out.println("生命周期:3、初始化");
    }

    public void destroyMethod(){
    
    
        System.out.println("生命周期:5、销毁");
    }

    @Override
    public String toString() {
    
    
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                '}';
    }
}

initMethod() および destroyMethod() は、Bean を構成することで初期化および破棄メソッドとして指定できることに注意してください。

③Beanの設定

画像-20230903151645308

<!-- 使用init-method属性指定初始化方法 -->
<!-- 使用destroy-method属性指定销毁方法 -->
<bean id="user" class=" com.jie.ioc.model.User" init-method="initMethod" destroy-method="destroyMethod">
    <property name="id" value="1001"/>
    <property name="username" value="admin"/>
    <property name="password" value="123456"/>
    <property name="age" value="23"/>
</bean>

④テスト

画像-20230903153213920

@Test
public void testLife() {
    
    
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.lifecycle.xml");
    User bean = ac.getBean("user", User.class);
    System.out.println("生命周期:4、通过IOC容器获取bean并使用");
    System.out.println(bean);
    ac.close();
}

⑤Beanポストプロセッサ

Bean のポストプロセッサーは、ライフサイクルの初期化の前後に追加の操作を追加します。BeanPostProcessor インターフェースを実装し、IOC コンテナーで構成する必要があります。Bean のポストプロセッサーは、特定の Bean のみですが、IOC コンテナ内のすべての Bean に対して実行されます

Bean ポストプロセッサを作成します。

package com.jie.ioc.model;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * @author 阿杰 [email protected]
 * @version 1.0
 * @date 2023/9/3 15:34
 */
public class MyBeanProcessor implements BeanPostProcessor {
    
    


    /**
     * 初始化之前执行
     *
     * @param bean
     * @param beanName
     * @return: java.lang.Object
     * @author 阿杰 [email protected]
     * @date: 2023/9/3 15:37
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        System.out.println("bean的后置处理器(初始化之前执行)");
        System.out.println("☆☆☆" + beanName + " = " + bean);
        return bean;
    }

    /**
     * 初始化之后执行
     *
     * @param bean
     * @param beanName
     * @return: java.lang.Object
     * @author 阿杰 [email protected]
     * @date: 2023/9/3 15:37
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
        System.out.println("bean的后置处理器(初始化之后执行)");
        System.out.println("★★★" + beanName + " = " + bean);
        return bean;
    }
}

IOC コンテナでポストプロセッサを構成します。

画像-20230903154101071

<!-- bean的后置处理器要放入IOC容器才能生效 -->
<bean id="myBeanProcessor" class="com.atguigu.spring6.process.MyBeanProcessor"/>

試験結果:

画像-20230903154049994

2.13 実験 12: FactoryBean

デモを続けてみましょう。私たちが現在デモしていることの多くは、XML での Bean 管理に基づいています。では、次に何を説明するのでしょうか? それはファクトリービーンと呼ばれます。

①はじめに

FactoryBean は、サードパーティのフレームワークを統合するために Spring によって提供される共通のメカニズムです。

通常のBeanとは異なり、FactoryBean型Beanを設定した場合、Bean取得時に取得するのはclass属性に設定したクラスのオブジェクトではなく、getObject()メソッドの戻り値となります。このメカニズムを通じて、Spring は複雑なコンポーネントを作成する詳細なプロセスや退屈な詳細を保護し、最も単純なユーザー インターフェイスのみを表示するのに役立ちます。

将来 Mybatis を統合するとき、Spring は FactoryBean メカニズムを通じて SqlSessionFactory オブジェクトを作成するのに役立ちます。

②UserFactoryBeanクラスを作成する

package com.jie.ioc.model;

import org.springframework.beans.factory.FactoryBean;

/**
 * 工厂Bean
 *
 * @author 阿杰 [email protected]
 * @version 1.0
 * @date 2023/9/3 15:48
 */
public class UserFactoryBean implements FactoryBean<User> {
    
    

    /**
     * 返回对象
     *
     * @return User
     */
    @Override
    public User getObject() throws Exception {
    
    
        return new User();
    }

    /**
     * 返回对象类型
     *
     * @return Class<User>
     */
    @Override
    public Class<?> getObjectType() {
    
    
        return User.class;
    }
}

③Beanの設定

画像-20230903155254768

<bean id="user" class="com.atguigu.spring6.bean.UserFactoryBean"></bean>

④テスト

画像-20230903155529682

このプロセス中に、UserFactoryBean を構成したオブジェクトの代わりに、単一インスタンスのユーザー オブジェクトを作成しました。

@Test
public void testUserFactoryBean(){
    
    
    //获取IOC容器
    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.factorybean.xml");
    User user = (User) ac.getBean("user");
    System.out.println(user);
}

2.14 実験 13: XML に基づく自動アセンブリ

自動組み立て:

指定された戦略に従って、IOC コンテナ内の特定の Bean を照合し、指定された Bean が依存するクラス タイプまたはインターフェイス タイプの属性に値を自動的に割り当てます。

①シーンシミュレーション

UserControllerクラスを作成する

package com.jie.ioc.controller;

/**
 *  用户控制器 
 *
 * @author 阿杰 [email protected]
 * @date 2023/9/3 16:16
 * @version 1.0
*/
public class UserController {
    
    

    private UserService userService;

    public void setUserService(UserService userService) {
    
    
        this.userService = userService;
    }

    public void saveUser(){
    
    
        userService.saveUser();
    }

}

インターフェースUserServiceの作成

package com.jie.ioc.service;

/**
 *  用户服务 
 *
 * @author 阿杰 [email protected]
 * @date 2023/9/3 16:16
 * @version 1.0
*/
public interface UserService {
    
    

    void saveUser();

}

UserServiceインターフェイスを実装するクラスUserServiceImplを作成します。

package com.jie.ioc.service.impl;

import com.jie.ioc.service.UserService;

/**
 *   用户服务实现类 
 *
 * @author 阿杰 [email protected]
 * @date 2023/9/3 16:16
 * @version 1.0
*/
public class UserServiceImpl implements UserService {
    
    

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
    
    
        this.userDao = userDao;
    }

    @Override
    public void saveUser() {
    
    
        userDao.saveUser();
    }

}

インターフェースUserDaoの作成

package com.jie.ioc.dao;

/**
 * 用户接口
 *
 * @author 阿杰 [email protected]
 * @version 1.0
 * @date 2023/9/3 16:17
 */
public interface UserDao {
    
    

    void saveUser();

}

UserDao インターフェイスを実装するクラス UserDaoImpl を作成します。

package com.jie.ioc.dao.impl;

import com.jie.ioc.dao.UserDao;

/**
 * 用户dao实现类
 *
 * @author 阿杰 [email protected]
 * @version 1.0
 * @date 2023/9/3 16:17
 */
public class UserDaoImpl implements UserDao {
    
    

    @Override
    public void saveUser() {
    
    
        System.out.println("保存成功");
    }

}

②Beanの設定

Bean タグの autowire 属性を使用してオートワイヤリング効果を設定する

自動組み立て方法:byType

byType: タイプに応じてIOCコンテナ内の互換性のあるタイプのBeanを照合し、プロパティに値を自動的に割り当てます

IOC で、互換性のあるタイプの Bean がプロパティに値を割り当てることができない場合、プロパティはアセンブルされません。つまり、値はデフォルト値の null になります。

IOC 内のプロパティに値を割り当てることができる互換性のあるタイプの Bean が複数ある場合、例外 NoUniqueBeanDefinitionException がスローされます。

<?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.xsd">

    <!-- 根据类型做自动装配 -->
    <bean id="userController" class="com.jie.ioc.controller.UserController" autowire="byType" />


    <bean id="userService" class="com.jie.ioc.service.impl.UserServiceImpl" autowire="byType"/>

    <bean id="userDao" class="com.jie.ioc.dao.impl.UserDaoImpl"/>

</beans>

自動アセンブリ方法: byName

byName: 自動的にアセンブルされた属性の属性名を Bean ID として使用して、割り当て用の IOC コンテナ内の対応する 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/spring-beans.xsd">

    <!-- 根据名称做自动装配 -->
    <bean id="userController" class="com.jie.ioc.controller.UserController" autowire="byName"/>

    <bean id="userService" class="com.jie.ioc.service.impl.UserServiceImpl" autowire="byName"/>
    <bean id="userServiceImpl" class="com.jie.ioc.service.impl.UserServiceImpl" autowire="byName"/>

    <bean id="userDao" class="com.jie.ioc.dao.impl.UserDaoImpl"/>
    <bean id="userDaoImpl" class="com.jie.ioc.dao.impl.UserDaoImpl"/>

</beans>

③テスト

画像-20230903163746526

@Test
void testAutoWireByXml(){
    
    
    ApplicationContext ac = new ClassPathXmlApplicationContext("autowire-xml.xml");
    UserController userController = ac.getBean(UserController.class);
    userController.saveUser();
}

3. アノテーションに基づいてBeanを管理する(☆)

Java 5 以降、Java にはアノテーションのサポートが追加されました。アノテーションはコード内の特別なマークであることがわかります。

コンパイル時、クラスのロード時、および実行時に読み取ることができ、対応する処理を実行できます。開発者は、元のコードやロジックを変更することなく、注釈を通じてソース コードに補足情報を埋め込むことができます。

Spring はバージョン 2.5 以降、アノテーション テクノロジの包括的なサポートを提供しており、アノテーションを使用して自動アセンブリを実装し、Spring の XML 構成を簡素化できます。

Spring でアノテーションによる自動アセンブリを実装する手順は次のとおりです。

  1. 依存関係を導入する
  2. コンポーネントのスキャンをオンにする
  3. アノテーションを使用して Bean を定義する
  4. 依存性注入

3.1 サブモジュール spring6-ioc-annotation をビルドする

①モジュールの構築

構築方法は以下の通りです: spring6-ioc-xml

②設定ファイルの導入

spring-ioc-xml モジュールのログ log4j2.xml を導入します

③依存関係を追加する

<dependencies>
    <!--spring context依赖-->
    <!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.0.11</version>
    </dependency>

    <!--junit5测试-->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.9.2</version>
    </dependency>

    <!--log4j2的依赖-->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.20.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j2-impl</artifactId>
        <version>2.20.0</version>
    </dependency>
</dependencies>

3.2 コンポーネントのスキャンをオンにする

Spring はデフォルトでは Bean のアセンブルにアノテーションを使用しないため、Spring の XML 設定の context:component-scan 要素を通じて Spring Bean の自動スキャン機能を有効にする必要があります。

この機能を有効にすると、Spring は指定したパッケージ (base-package 属性の設定) およびそのサブパッケージ内のすべてのクラスを自動的にスキャンし、クラスに @Component アノテーションが使用されている場合、そのクラスはコンテナにアセンブルされます。

注: context:component-scan 要素を使用して自動スキャン機能を有効にする前に、まず XML 設定の第 1 レベルのタグにコンテキスト関連の制約 (名前空間) を追加する必要があります。

画像-20230903174106993

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">


</beans>

状況 1: 最も基本的なスキャン方法

<!-- 开启组件扫描 -->
<context:component-scan base-package="com.jie.annotation"/>

このように、すべてのクラスがアノテーションとそのサブパッケージの下に構築されている限り、クラスで @Component アノテーションが使用されている場合、クラスはコンテナにアセンブルされます。

ケース 2: 除外するコンポーネントを指定する

<context:component-scan base-package="com.jie.annotation">
    <!-- context:exclude-filter标签:指定排除规则 -->
    <!-- 
             type:设置排除或包含的依据
            type="annotation",根据注解排除,expression中设置要排除的注解的全类名
            type="assignable",根据类型排除,expression中设置要排除的类型的全类名
        -->
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    <!--<context:exclude-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>-->
</context:component-scan>

シナリオ 3: 指定されたコンポーネントのみをスキャンする

<context:component-scan base-package="com.jie.annotation" use-default-filters="false">
    <!-- context:include-filter标签:指定在原有扫描规则的基础上追加的规则 -->
    <!-- use-default-filters属性:取值false表示关闭默认扫描规则 -->
    <!-- 此时必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类 -->
    <!--
             type:设置排除或包含的依据
            type="annotation",根据注解排除,expression中设置要排除的注解的全类名
            type="assignable",根据类型排除,expression中设置要排除的类型的全类名
        -->
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    <!--<context:include-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>-->
</context:component-scan>

通常、最初のものを使用するだけで十分です。

3.3 アノテーションを使用した Bean の定義

Spring は、次の複数のアノテーションを提供します。これらのアノテーションは、Java クラスに直接アノテーションを付けて Spring Bean として定義できます。

注釈 説明する
@成分 SpringでBeanを記述する際に使用されるアノテーションであり、コンテナ内のコンポーネント(Bean)のみを表現する一般的な概念であり、Service層やDao層などアプリケーションのどのレベルでも利用できます。使用する場合は、対応するクラスにアノテーションをマークするだけで済みます。
@リポジトリ このアノテーションはSpringにおいてデータアクセス層(Dao層)のクラスをBeanとして識別するために使用され、その機能は@Componentと同じである。
@サービス このアノテーションは通常ビジネス層(サービス層)で動作し、Springにおいてビジネス層のクラスをBeanとして識別するために使用され、機能は@Componentと同じです。
@コントローラ このアノテーションは通常、コントロール層(SpringMVCのControllerなど)で動作し、Springにおいてコントロール層のクラスをBeanとして識別するために使用され、その機能は@Componentと同じです。

3.4 実験 1: @Autowired インジェクション

@Autowired アノテーションを単独で使用し、デフォルトで型に基づいてアセンブルします[デフォルトはbyTypeです]

ソースコードを表示:

画像-20230903175524380

ソースコードの枠で囲まれた部分を見てください。これは何ですか? これは、規定されたアノテーションであり、いくつかの特定の詳細が含まれるメタ アノテーションとして理解できます。最初の部分を見てみると、これは @Target と呼ばれ、このアノテーションが使用できる場所を示しています。

たとえば、@Autowired は次の場合に使用できます。

  • 施工方法について
  • 方法
  • 形参上
  • 属性
  • 注釈

次に、アノテーションには必須の属性があります。デフォルト値は true で、これは、注入された Bean が注入中に存在する必要があることを意味します。存在しない場合は、エラーが報告されます。required 属性が false に設定されている場合、注入された Bean が存在するかどうかは関係ないことを意味します。存在する場合は注入され、存在しない場合はエラーは報告されません。

① シナリオ 1: 属性の注入

UserDaoインターフェースを作成する

package com.jie.annotation.dao;

/**
 * 用户dao接口
 *
 * @author 阿杰 [email protected]
 * @version 1.0
 * @date 2023/9/3 18:02
 */
public interface UserDao {
    
    

    public void print();
}

UserDaoImpl実装を作成する

package com.jie.annotation.dao.impl;


import com.jie.annotation.dao.UserDao;
import org.springframework.stereotype.Repository;

/**
 * 用户dao实现类
 */
@Repository
public class UserDaoImpl implements UserDao {
    
    

    @Override
    public void print() {
    
    
        System.out.println("Dao层执行结束");
    }
}

UserServiceインターフェースの作成

package com.jie.annotation.service;

/**
 *  用户服务接口 
 *
 * @author 阿杰 [email protected]
 * @date 2023/9/3 18:03
 * @version 1.0
*/
public interface UserService {
    
    

    public void out();
}

UserServiceImpl実装クラスを作成する

package com.jie.annotation.service.impl;


import com.jie.annotation.dao.UserDao;
import com.jie.annotation.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 *  服务层实现类 
 *
 * @author 阿杰 [email protected]
 * @date 2023/9/3 18:03
 * @version 1.0
*/
@Service
public class UserServiceImpl implements UserService {
    
    

    @Autowired
    private UserDao userDao;

    @Override
    public void out() {
    
    
        userDao.print();
        System.out.println("Service层执行结束");
    }
}

UserControllerクラスを作成する

package com.jie.annotation.controller;


import com.jie.annotation.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

/**
 * 控制器层
 *
 * @author 阿杰 [email protected]
 * @version 1.0
 * @date 2023/9/3 18:04
 */
@Controller
public class UserController {
    
    

    @Autowired
    private UserService userService;

    public void out() {
    
    
        userService.out();
        System.out.println("Controller层执行结束。");
    }

}

テスト 1

画像-20230903180720473

②シナリオ 2: セットインジェクション

UserServiceImpl クラスを変更する

画像-20230903181024363

UserControllerクラスを変更する

画像-20230903181107727

テスト: 呼び出し成功

画像-20230903181126839

③シナリオ 3: コンストラクター メソッドのインジェクション

UserServiceImpl クラスを変更する

画像-20230903181325615

UserControllerクラスを変更する

画像-20230903181344566

テスト: 呼び出し成功

画像-20230903181358517

④シナリオ4:仮パラメータへの注入

UserServiceImpl クラスを変更する

画像-20230903181445531

UserControllerクラスを変更する

画像-20230903181506016

テスト: 呼び出し成功

画像-20230903181520643

⑤シナリオ 5: コンストラクターは 1 つだけ、アノテーションなし

UserServiceImpl クラスを変更する

画像-20230903181801900

テストに合格しました

画像-20230903181817121

パラメーターを持つコンストラクターが 1 つだけの場合は、 @Autowired アノテーションを省略できます。

注: 複数のコンストラクターがある場合はどうなるでしょうか?

画像-20230903182039985

試験結果:

画像-20230903182058788

⑥シナリオ6: @Autowiredアノテーションと@Qualifierアノテーションの組み合わせ

Daoレイヤー実装を追加

package com.jie.annotation.dao.impl;


import com.jie.annotation.dao.UserDao;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaoRedisImpl implements UserDao {
    
    

    @Override
    public void print() {
    
    
        System.out.println("Redis Dao层执行结束");
    }
}

テスト:

画像-20230903182340972

エラー メッセージは次のとおりです: アセンブルできません。UserDao Bean の数は 2 です。

この問題を解決するにはどうすればよいでしょうか? もちろん、byNameは必須であり、その名前に基づいてアセンブリが実行されます。

UserServiceImpl クラスを変更する

画像-20230903182527398

要約する

  • @Autowired アノテーションは、プロパティ、コンストラクター、コンストラクター パラメーター、およびセッター メソッドに表示できます。
  • パラメーターを持つコンストラクターが 1 つだけの場合は、 @Autowired アノテーションを省略できます。()
  • @Autowired アノテーションは、デフォルトでタイプに基づいて挿入されます。名前に基づいて注入する場合は、 @Qualifier アノテーションを付けて使用する必要があります。

3.5 実験 2: @リソース注入

@Resourceアノテーションによって属性の注入を完了することもできます。では、**@Autowired** アノテーションとの違いは何でしょうか?

  • @Resource アノテーションは JDK 拡張パッケージに含まれており、これは JDK の一部であることを意味します。したがって、このアノテーションは標準的なアノテーションであり、より多用途です。(JSR-250 標準で指定されたアノテーション タイプ。JSR は Java 仕様提案です。)
  • @Autowired アノテーションは Spring フレームワーク独自のものです。
  • @Resource アノテーションはデフォルトでは名前に応じて byName でアセンブルされますが、名前を指定しない場合は属性名が名前として使用されます。名前で見つからない場合は、タイプ byType によるアセンブリが自動的に開始されます。
  • @Autowired アノテーションはデフォルトで型に基づいて byType でアセンブルしますが、名前に基づいてアセンブルしたい場合は @Qualifier アノテーションと併用する必要があります。
  • @Resource アノテーションはプロパティとセッター メソッドで使用されます。
  • @Autowired アノテーションは、プロパティ、セッター メソッド、コンストラクター、およびコンストラクター パラメーターで使用されます。

@Resource アノテーションは JDK 拡張パッケージに属しているため、JDK には含まれていません。次の追加の依存関係を導入する必要があります: [ JDK8 の場合、追加の依存関係を導入する必要はありません。JDK11 より上位または JDK8 より下位の場合は、次の依存関係を導入する必要があります。

<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>

① シナリオ 1: 名前に従って注入

UserDaoImpl クラスを変更する

画像-20230903183345700

UserServiceImpl クラスを変更する

画像-20230903183434415

テストに合格しました

画像-20230903183458636

②シナリオ2:名前不明の注射

UserDaoImpl クラスを変更する

画像-20230903183703309

UserServiceImpl クラスを変更する

画像-20230903183733990

テストに合格しました

画像-20230903183755279

名前を指定せずに @Resource アノテーションが使用された場合でも、検索は名前 (属性名) に基づいて行われます。

③シナリオ3のその他の状況

UserServiceImpl クラスを変更します。myUserDao1 属性名は存在しません。

画像-20230903183919732

テスト例外

画像-20230903183940020

例外情報によると、名前が見つからない場合は当然 byType が起動してインジェクションされることがわかっていますが、上記のエラーは UserDao インターフェース配下に実装クラスが 2 つあるために発生します。したがって、型注入に基づいてエラーが報告されます。

@Resource のセットインジェクションは単独でテストできます

要約する

@Resource アノテーション: デフォルトは ByName インジェクション、name が指定されていない場合は属性名を name とみなし、名前が見つからない場合は byType インジェクションが実行されます。Type によって注入される場合、特定のタイプの Bean は 1 つだけ存在できます。

3.6 Spring の完全なアノテーションの開発

完全なアノテーション開発とは、Spring 構成ファイルを使用しなくなり、構成ファイルを置き換える構成クラスを作成することを意味します。

画像-20230903184921430

テストクラス

画像-20230903185115969

おすすめ

転載: blog.csdn.net/weixin_53041251/article/details/132653663