Sping の研究ノート (例付き、超詳細)

目次

1. まずは春とは何かについて話しましょう

1.1 Spring コードを作成するためにインポートする必要がある依存関係: (多くの jar パッケージが含まれています)

 2. 制御反転 (IOC) の理論的導出

2.1 TestでSpringのコンテキストオブジェクトを取得する

2.2 依存性の注入

2.3 拡張: C タグと P タグのインジェクション

3. 制御の反転

4. IOC がオブジェクトを作成する方法

4.1 添字の割り当てですが、パラメーターを使用してコンストラクターを作成する必要があります

4.2 タイプによる作成は非推奨になりました

4.3 パラメータを通じて直接設定する

5. データベース接続プール

6.Beanスコープ

6.1 シングルトン モード: (Spring のデフォルト メカニズム)

6.2 プロトタイプパターン

6.3. その他のリクエスト、セッション、アプリケーション

7.Bean自動アセンブリ

7.1 アノテーションを利用した自動アセンブリの実現

7.1.1@自動配線

7.1.2 インポートの制約

7.1.3 Beanの実装

7.1.4 プロパティの注入

7.2 設定アノテーションのサポート

7.2.1 @Autowired と @Resource の違い

7.3 XML とアノテーションの比較

8. プロキシモード

8.1 AOP の使用目的

8.2 静的プロキシ

8.3 静的プロキシについての深い理解

9. 動的プロキシ

9.1 例

9.2 動的プロキシのより深い理解

9.3 プロキシモードの概要

10. 反射を理解する

11.AOP

11.1 AOPとは

11.2 春における Aop の役割 

 11.2.1 Spring AOPの2つのプロキシメソッド

11.3 トピックから始めて、最初にパッケージをガイドする

11.4 具体的には3つの方法に分かれる

11.4.1 最初の方法: オリジナルの SpringAPI インターフェースを使用する

11.4.2 方法 2: Aop を実装するようにクラスをカスタマイズする

11.4.3 方法 3 アノテーションを使用して実装する

11.5 AOP「ハートブリーディング」の概要

12. 宣言的トランザクション 

12.1 トランザクションの 4 つの属性

12.2 Spring のトランザクション管理 

12.2.1 トランザクションマネージャー 

12.3 Spring トランザクション伝播機能 

12.4 ヘッダー ファイルの制限付きインポート 

12.5 ケース 

13. 定期的な自己要約


1. まずは春とは何かについて話しましょう


    1.Spirng は無料のオープンソース コンテナ (フレームワーク) です;
    2.Spring は軽量で非侵襲的なフレームワークです;
    3.制御の反転 (IOC)、アスペクト指向プログラミング (AOP);
    4. サポート トランザクション処理、サポートフレームワーク統合!



1.1 Spring コードを作成するためにインポートする必要がある依存関係: (多くの jar パッケージが含まれています)

地址:<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>6.0.2</version>
</dependency>

 
2. 制御反転 (IOC) の理論的導出

  • 本質的には、プログラマがオブジェクトの作成を管理する必要性が解決されシステムの結合が軽減されます
  • プログラムは受動的にインターフェイスを提供し、主導権はユーザーにあり、ユーザーの操作を取得して、対応するメソッドを呼び出すだけで済みます。
  • 制御の反転は、記述 (XML または注釈) およびサードパーティを通じて特定のオブジェクトを生成または取得する方法です。
  • Springで制御の反転を実装するのはIOCコンテナであり、その実装方法は依存性注入(DI)である

2.1 TestでSpringのコンテキストオブジェクトを取得する

ApplicationContext context = new ClassPathXmlApplicationContext("xml文件");

        次に、必要な人を入手してください

2.2 依存性の注入

例:

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}
//对应不同的注入方式
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address.toString() +
                ", books=" + Arrays.toString(books) +
                ", hobbys=" + hobbys +
                ", card=" + card +
                ", games=" + games +
                ", wife='" + wife + '\'' +
                ", info=" + info +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String[] getBooks() {
        return books;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public List<String> getHobbys() {
        return hobbys;
    }

    public void setHobbys(List<String> hobbys) {
        this.hobbys = hobbys;
    }

    public Map<String, String> getCard() {
        return card;
    }

    public void setCard(Map<String, String> card) {
        this.card = card;
    }

    public Set<String> getGames() {
        return games;
    }

    public void setGames(Set<String> games) {
        this.games = games;
    }

    public String getWife() {
        return wife;
    }

    public void setWife(String wife) {
        this.wife = wife;
    }

    public Properties getInfo() {
        return info;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }
}

豆.xml

<?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/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
    <bean id="address" class="com.gcx.pojo.Address">
        <property name="address" value="青岛"/>
    </bean>
    <bean id="student" class="com.gcx.pojo.Student">
<!--        第一种普通值注入 value-->
        <property name="name" value="gcx"/>
<!--        第二种注入bean注入, ref-->
        <property name="address" ref="address"/>
<!--        数组注入-->
        <property name="books">
            <array>
                <value>红楼梦</value>
                <value>西游记</value>
                <value>水浒传</value>
                <value>三国演义</value>
            </array>
        </property>
<!--        List-->
        <property name="hobbys">
            <list>
                <value>听歌</value>
                <value>看电影</value>
                <value>玩游戏</value>
            </list>
        </property>
<!--        map-->
        <property name="card">
            <map>
                <entry key="身份证" value="111111111111111111"/>
                <entry key="银行卡" value="684546554466455545"/>
            </map>
        </property>
<!--        set-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>COC</value>
                <value>BOB</value>
            </set>
        </property>
<!--        null-->
        <property name="wife">
            <null/>
        </property>
<!--        Properties-->
        <property name="info">
            <props>
                <prop key="studyId">78945621</prop>
                <prop key="phone">20221206</prop>
                <prop key="姓名">小明</prop>
            </props>
        </property>
    </bean>


</beans>

 テストテスト

public class Mytest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.toString());
    }

2.3 拡張: C タグと P タグのインジェクション

public class User {
    private String name;
    private int age;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

UserBean.xml

<?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"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!--需要先导入约束(第4 5行)-->
    <!--    P命名空间注入-->
    <bean id="User" class="com.gcx.pojo.User" p:name="gcx" p:age="18"/>
<!--C命名空间注入 通过有参无参注入-->
    <bean id="user2" class="com.gcx.pojo.User" c:age="18" c:name="cxg"/>
</beans>

テストテスト:

@Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("UserBean.xml");
        User user = (User) context.getBean("user2");//测试P标签对应beanid为user
        System.out.println(user);
    }


3. 制御の反転


    制御: オブジェクトの作成を誰が制御するか、従来のアプリケーションのオブジェクトはプログラム自体によって作成されます; Spring を使用した後、オブジェクトは Spring によって作成されます 反転: プログラム自体はオブジェクトを作成せず、受動的受信オブジェクトになります
    。
    依存性注入: set メソッドを使用して注入すること
    IOC は、能動的なプログラミングから受動的な受信に変化するプログラミングの概念です。


さまざまな操作を実現するには、XML 構成ファイルを変更するだけで済みます。いわゆる IOC とは、オブジェクトが Spring によって作成、管理、およびアセンブルされることを意味します。 

4. IOC がオブジェクトを作成する方法


引数なしのコンストラクターを使用する

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


4.1 添字の割り当てですが、パラメーターを使用してコンストラクターを作成する必要があります
 

<constructor-arg index="0" value="456"/>


4.2 タイプによる作成は非推奨になりました

<constructor-arg type="java.lang.String" value="gcx"/>


4.3 パラメータを通じて直接設定する

<bean id="user" class="com.gcx.User">
        <constructor-arg name="name" value="gcx"/>
</bean>

5. データベース接続プール


プーリング技術: 事前にリソースを用意しておき、
来訪時に事前に用意した接続にリンクする 最小接続数: よく使用する接続数に応じて設定
最大接続数: 最大接続数を設定接続数が最大接続数を超えると、列で待機します
待機タイムアウト: 待機時間がキュー待機時間を超えると、自動的に待機時間が終了し、エラーが表示されます

接続プールを作成し、インターフェイス DataSource を実装します
共通データプール:

  • DBCP (jar パッケージのインポート)
  • c3p0 (jar パッケージのインポート)
  • ドルイド:アリババ

これらのデータベース接続プールを使用した後は、データベース コードを記述する必要はありません。
どのデータ ソースが使用されても、本質は同じです。データソース インターフェイスやメソッドは変わりません。

6.Beanスコープ


6.1 シングルトン モード: (Spring のデフォルト メカニズム)

<!--<bean id="accountService" class="com.something.DefaultAccountService"/>
(singleton scope is the default) -->
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>


6.2 プロトタイプパターン

欠点: コンテナから取得するたびに、新しいオブジェクトが生成されます (リソースを無駄にします)。
 

<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>


6.3. その他のリクエスト、セッション、アプリケーション

これらは Web 公開でのみ使用できます。
公式ウェブサイト: リクエスト、セッション、アプリケーション、および WebSocket のスコープは、Web 対応の Spring ApplicationContext 実装 (XmlWebApplicationContext など) を使用する場合にのみ使用できます。 これらのスコープをClassPathXmlApplicationContext などの 
通常の Spring IoC コンテナで使用すると 、不明な Bean スコープに関する不平を示すIllegalStateExceptionスローされます。

7.Bean自動アセンブリ


3 つの自動組み立て方法:

                                  1. XML で構成を表示
                                  2. Java で構成を表示
                                  3. 暗黙的な自動アセンブリ Bean [重要] (byName、byType)


7.1 アノテーションを利用した自動アセンブリの実現

1. aop の jar パッケージをインポートする必要があります (Maven プラグインを確認してください)。

2. @Autowired (一般的に使用)、@Resource

7.1.1@自動配線

例:

public class Cat {
    public void shout(){
        System.out.println("miao");
    }
}
public class Dog {
    public void shout(){
        System.out.println("wang");
    }
}
public class People {
//    如果显示定义了Autowired属性的required为false,说明这个属性可以为null,否则不允许为空;
//    @Autowired(required = false)
    @Autowired
    @Qualifier(value = "cat11")
//    @Qualifier(value = "beanid")当自动装配无法通过一个注解完成时,用来指定一个唯一的bean对象注入
    private Cat cat;
    @Autowired
    @Qualifier(value = "dog11")
    private Dog dog;
    private String name;

    @Override
    public String toString() {
        return "People{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

 beans.xml (非標準)

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config/>
<!--    使用Autowired可以不用set方法,前提是自动装配的属性在IOC容器中存在且符合名字byName-->
        <bean id="cat" class="com.gcx.pojo.Cat"/>
        <bean id="cat11" class="com.gcx.pojo.Cat"/>
        <bean id="dog" class="com.gcx.pojo.Dog"/>
        <bean id="dog11" class="com.gcx.pojo.Dog"/>
<!--    自动装配:autowire    byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid(必须对应相同,所有bean的id唯一)
                    byType:会自动在容器上下文中查找,和自己对象属性类型对应相同bean(必须保证所有bean的class全局唯一)-->
    <bean id="people" class="com.gcx.pojo.People">
        <property name="name" value="gcx"/>
<!--        <property name="cat" ref="cat"/>-->
<!--        <property name="dog" ref="dog"/>-->
     </bean>
<!--    开启注解支持-->

</beans>

テストテスト

public class Mytest {
    @Test
    public void test(){
        ApplicationContext Context = new ClassPathXmlApplicationContext("beans.xml");
        People people = (People) Context.getBean("people");
        people.getDog().shout();
        people.getCat().shout();
    }
}


7.1.2 インポートの制約

xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd


7.1.3 Beanの実装


注釈スキャン パッケージを指定して、注釈をスキャンするパッケージを構成します

<context:component-scan base-package="com.gcx"/>


7.1.4 プロパティの注入


    (1) setメソッドを提供する必要はなく、直接@value("value");を追加する
    (2)setメソッドを提供する場合は、setメソッドに@value("value");を追加する。


7.2 設定アノテーションのサポート

<context:annotation-config/> //若使用注解就必须开启,否则注入为空


@Autowired アノテーションの自動アセンブリ環境がより複雑で、アノテーション [@Autowired] を通じて自動アセンブリを完了できない場合は、 @Qualifier(value = "xxx") を使用して @Autowired の使用を構成し、ユニークなBeanオブジェクトのインジェクション!


7.2.1 @Autowired と @Resource の違い


1. どちらも自動アセンブリに使用され、属性フィールドに配置できます
2. @Autowired は byType のメソッドによって実装されます
3. @Resource はデフォルトで byName のメソッドです。同じ名前が見つからない場合は、タイプ達成!
どちらも見つからない場合は、エラーが報告されます。
4. 実行順序が異なります。デフォルトでは、@Autowired は byType のメソッドによって実装され、@Resource は byName のメソッドによって実装されます。

7.3 XML とアノテーションの比較


1. XML は構造が明確でメンテナンスが容易であらゆるシーンに適用可能
2. アノテーションがクラスで提供されていないため利用できず、開発が簡単で便利

XML とアノテーションの統合開発: Bean を管理するためのベスト プラクティスXML を推奨し、アノテーションによって属性の挿入を完了させます     /**使用中、スキャンは必要ありません。スキャンはクラスのアノテーション用です*/
    

8. プロキシモード

この部分では、まずリフレクションとは何かを理解する必要があります。リフレクションとは何かを理解することは、プロキシ モードとは何かを理解するのに役立ちます。詳細については、カタログ 10を参照してください。

[AOP (アスペクト指向プログラミング (AOP)) の基礎となるメカニズムは動的プロキシです。


8.1 AOP の使用目的

元のコードを変更することなく、元の機能の拡張が実現されます。これが AOP の中心的なアイデアです


プロキシ モードは次のように分類されます。
        1. 静的プロキシ
        2. 動的プロキシ


静的プロキシ ロール分析
/**
    * 抽象ロール: 通常、インターフェイスまたは抽象クラス (メソッドまたは動作に相当) を使用して実装されます。
    * 実際のロール: プロキシされるロール
    * プロキシ ロール: 実際のロールとして機能し、プロキシした後実際のロール (一般的に) いくつかの組み込み操作が存在します。
    * クライアント: プロキシ ロールを使用して一部の操作を実行します
*/


静的エージェントの長所と短所
/**
*利点:
* 1. 本当の役割をより純粋にすることができます。一部の公的なものに注意を払わなくなります。 *
2. 公的業務はエージェントによって行われます。分業は*3 .
パブリックビジネスが拡大すると一元化され便利になる
*デメリット:
*クラス(リアルロール)、プロキシクラス(エージェントロール)が増え、記述するコードが2倍になり、作業負荷がかかるが増加し、開発効率が低下する

8.2 静的プロキシ

例: [実際の役割: 家主、抽象的な役割 (方法): 家を借りる、エージェントの役割: 仲介者、顧客: 家を購入する人] 静的エージェント全体を説明します。

家主:

//房东
public class Host implements Rent{

    @Override
    public void rent() {
        System.out.println("房东出租房子");
    }
}

家を借りる:

//租房
public interface Rent {
    void rent();
}

仲介者:

//中介
//这里中介去实现了租房子这个方法,就相当于中介帮助房东出租房子
public class ZhongJie implements Rent{
//去找到房东,为了获取房源
    private Host host;

    public ZhongJie() {
    }
//为房东创建实参,为了实现出租房子的方法(行为)
    public ZhongJie(Host host) {
        this.host = host;
    }

    public void rent() {
//通过房东去.出来买房子的方法
        host.rent();
//这是中介(代理对象)自带的一些方法
        seeHouse();//看房子
        hetong();//签合同
        takeMoney();//赚差价
        sell();//卖出房子
    }
/**
*对应的中介自带的方法
*/
//    看房
    public void seeHouse(){
        System.out.println("中介带你看房");
    }
//签合同
    public void hetong(){
        System.out.println("中介签合同");
    }
//赚差价
    public void takeMoney(){
        System.out.println("中介收中介费");
    }
//卖出房子
    public void sell(){
        System.out.println("卖出房子");
    }
}

家を買う人:

public class Empty {
    public static void main(String[] args) {
//        房东要租房子
        Host host = new Host();
//        host.rent();
//        房东去找中介,中介帮房东租房子,但是代理角色一般会有一些自带的操作!
        ZhongJie zhongJie = new ZhongJie(host);
//        有了中介,租房子的人不需要面对房东,直接找中介即可
        zhongJie.rent();
    }
}

出力結果:

房东要出租房子
中介带你看房
中介签合同
中介收中介费
卖出房子

上記のコードから、家主は売りたい家のメソッド(動作)とリストのみを提供し、残りは家が売れるまでエージェント(仲介者)によって提供されることが容易にわかります。あちらへ;

同様に、他の操作が必要な場合は、仲介で直接実装できます。

 8.3 静的プロキシについての深い理解

オリジナルのコードを変更することなく、オリジナルの機能強化を実現

 

//先去写出一些方法
public interface UserService {
    void add();
    void delete();
    void update();
    void query();
}
然后去用实现类实现接口内的方法
public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }

    @Override
    public void update() {
        System.out.println("更改了一个用户");
    }

    @Override
    public void query() {
        System.out.println("查询了一个用户");
    }
}

この時点でTestテストを直接書くと

public class Test {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        userService.add();
    }
}

結果は次のようになるでしょう

增加了一个用户

他のメソッドを呼び出すことは、sout の内容を表示することでもありますが、この時点で、親愛なる当事者 A が次の要求を出しました。

バックグラウンドでどのメソッドを使用するかをユーザーに伝えるために、元の各出力に基づいて新しい出力を追加する必要があります。

 まず、最も直接的な方法は、実装クラスに別の sout を記述して、使用するメソッドを出力することですが、メソッドに 100 がある場合はどうなるでしょうか? 1000 がある場合はどうなりますか? それ以上ある場合はどうなりますか? 1 つずつ追加することはできませんしたがって、AOP (アスペクト指向プログラミング) メソッドを使用する必要があります。これは仲介者をセットアップするのと同じで、最初に元のメソッドを取得し、次に新しいコンテンツを追加します。

public class UserServiceDaiLi implements UserService{
//获取原有实现类方法
    private UserServiceImpl userservice;
//设置set方法
    public void setUserservice(UserServiceImpl userservice) {
        this.userservice = userservice;
    }
//因为在这里实现了UserService接口,所以去重写(可以不写重写注释,实质上也不算重写)原来内部的信息
    @Override
    public void add() {
        log("add");
        userservice.add();
    }

    @Override
    public void delete() {
        log("delete");
    userservice.delete();
    }

    @Override
    public void update() {
        log("update");
userservice.update();
    }

    @Override
    public void query() {
        log("query");
   userservice.query();
    }
//这里去写我们要新添加的内容,然后在上边的方法中去添加该方法即可达到目的
    public void log(String msg){
//        添加日志
        System.out.println("[Debug]使用了"+msg+"方法");
    }
}

テストテスト:

public class Test {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        UserServiceDaiLi DaiLi = new UserServiceDaiLi();
        DaiLi.setUserservice(userService);
//因为要输出的是daili内部新写的内容
        DaiLi.add();

    }
}

出力は次のとおりです。

[Debug]使用了add方法
增加了一个用户

9. 動的プロキシ

/**メリット:
* 1. 本当の役割をより純粋にすることができます。一部の公的なものに注意を払わなくなります。
* 2. 公的業務はエージェントによって完了します。分業が実現します。
* 3. 公共ビジネスは展開します
* 4. 動的プロキシ クラスは、一般にビジネスのタイプに対応するインターフェイスをプロキシし
5. 動的プロキシ クラスは、同じインターフェイスが実装されている限り、複数のクラスをプロキシできます 
*/

---- この部分は抽象的でわかりにくいため、コードを直接アップロードし、具体的な説明はコード内に記述します

----まず、静的プロキシのデータを例に挙げます。

9.1 例

家主:

//房东
public class Host implements Rent {

    @Override
    public void rent() {
        System.out.println("房东要出租房子");
    }
}

家を借りる:

//租房
public interface Rent {
    void rent();
}

プロキシ オブジェクト (正式には ProxyInvocationHandler、わかりやすいように DaiLi~~~ という名前):

//使用这个类自动生成代理角色
public class DaiLiInvocationHandler implements InvocationHandler {

//    被代理的接口
    private Rent rent;

    public void setRent(Rent rent) {
        this.rent = rent;
    }

//    生成得到代理类

    /**
     * @return
     * getClassLoader() 是为了加载类在哪个位置
     * getInterfaces() 表示要代理的接口是哪一个
     * this 代表InvocationHandler本身
     */
     public Object getProxy(){
       return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
     }

    //(真正的处理是靠invoke方法执行)处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//        动态代理的本质就是使用反射机制实现
        seeHouse();
        Object result = method.invoke(rent,args);
        takeMoney();
        return result;
    }
    public void seeHouse(){
        System.out.println("中介带去看房子");
     }
     public void takeMoney(){
        System.out.println("中介收差价");
     }

}

家を売る人:

public class Client {
    public static void main(String[] args) {
//        真实角色
        Host host = new Host();
//        代理角色(暂时不存在,需要去调用set设置)
        DaiLiInvocationHandler dih = new DaiLiInvocationHandler();
//        通过调用程序处理角色,来处理我们调用的接口对象!
        dih.setRent(host);
        Rent proxy = (Rent) dih.getProxy();
        proxy.rent();
    }
}

出力結果:

中介带去看房子
房东要出租房子
中介收差价

9.2 動的プロキシのより深い理解

動的プロキシの詳細については、8.3 に従ってください。

プロキシ オブジェクト:

//使用这个类自动生成代理角色
public class DaiLiInvocationHandler implements InvocationHandler {
//代理谁:
    //被代理的接口
    private Object target;
//        setter
    public void setTarget(Object target) {
        this.target = target;
    }

    /**
     * @return
     * getClassLoader() 是为了加载类在哪个位置
     * getInterfaces() 表示要代理的接口是哪一个
     * this 代表InvocationHandler本身
     */
//生成得到代理类(固定写法,只需要更改需要实现的接口):
     public Object getProxy(){
       return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
     }
//调用代理程序的一些方法
    //(真正的处理是靠invoke方法执行)处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //动态代理的本质就是使用反射机制实现
        /**
         * 如果这里的msg去设置单独的一个方法,
         * 那么如果我去调用删除方法,就还要在log内更改为delete
         * 但如果通过invoke的method去.出来getName,则只需要去更改前端的调用方法
         * 后端自动的去动态处理输出的内容
         */
        //        log("add");
        log(method.getName());
        Object result = method.invoke(target,args);
        return result;
    }
//    设置新增日志
    public void log(String msg){
        System.out.println("[Debug]使用了"+msg+"方法");
    }

}

ユーザー(家を借りる人):

public class Customer {
    public static void main(String[] args) {
//        真实角色
        UserServiceImpl userService = new UserServiceImpl();
//        代理角色(暂时不存在,需要去设置)
        DaiLiInvocationHandler dih = new DaiLiInvocationHandler();
        dih.setTarget(userService);//设置要代理的对象
        UserService proxy = (UserService) dih.getProxy();
        proxy.delete();
    }
}

出力結果:

[Debug]使用了delete方法
删除了一个用户

9.3 プロキシモードの概要

Zhoumu の代理店モデルの概要は次のとおりです。

1. まず、動的プロキシの「反射」問題については、まず反射とは何かを理解し、次にプロキシ モードのコードを確認する必要があります。

2. 第 2 に、プロキシ モードでは、名前が示すように、コードが煩雑に見えず、すべてのビジネス オペレーションがプロキシ オブジェクトに引き渡されるように、コードが明確な役割分担を達成できるようにするためのプロキシ オブジェクトが必要です。後のメンテナンス作業でコードを変更する必要はありませんが、これはオープンとクローズの原則に違反します (つまり、ソフトウェア エンティティは元のコードを変更せずに拡張しようとする必要があります)。

3. 最後にアーキテクチャ(ルーチン)を理解する 変更しない部分が多いのでメモするだけでよい 後のメンテナンスでは指定内容を変更すればメンテナンス完了となる 実オブジェクト、プロキシオブジェクト、抽象メソッドとフロントエンドの呼び出しと実装の関係。

 10. 反射を理解する

1. 反省とは

実行状態では、どのクラスでも、このクラスのすべてのプロパティとメソッドを知ることができます。

どのオブジェクトでも、そのメソッドとプロパティを呼び出すことができます。

この動的に情報を取得し、オブジェクトのメソッドを動的に呼び出す機能をJava言語のリフレクション機構と呼びます。

2. リフレクションの利点:

リフレクションにより、プログラムの柔軟性と拡張性が向上し、結合が減少し、自己適応性が向上します。これにより、プログラムはターゲット クラスを事前にハードコーディングすることなく、任意のクラスのオブジェクトを作成および制御できます。

3. 反射のデメリット

パフォーマンスの問題。リフレクションの使用は基本的に解釈操作であり、フィールドやメソッドへのアクセスに使用すると、直接コードよりもはるかに遅くなります。したがって、リフレクション メカニズムは主に、高い柔軟性と拡張性が必要なシステム フレームワークで使用され、通常のプログラムには推奨されません。

11.AOP

11.1 AOPとは

AOP(Aspect Oriented Programming)とは、アスペクト指向プログラミングのことで、プリコンパイルとランタイムダイナミックプロキシによるプログラム機能の一元的な維持を実現する技術です。AOP は、ソフトウェア開発のホットスポットである OOP の継続であり、Spring フレームワークの重要な内容であり、関数型プログラミングの派生パラダイムです。AOP を使用すると、ビジネス ロジックのさまざまな部分を分離することができます。これにより、ビジネス ロジックのさまざまな部分間の結合度が低減され、プログラムの再利用性が向上し、同時に開発の効率も向上します。

11.2 春における Aop の役割 

AOP 用語:

1. ジョインポイント

        メソッド呼び出しや例外実行など、プログラム実行プロセス内の特定のノードは通常、メソッド実行です。

2. ポイントカット

        処理が必要な接続ポイントを指します。すべてのメソッドの実行が接続ポイントであり、特定の接続ポイントがエントリ ポイント (インターセプトされた接続ポイント) になります。

3. ターゲット

        通知されるオブジェクト、つまりプロキシのターゲットオブジェクトを指します。

4. 通知(アドバイス)

        拡張としても知られており、アスペクトによって特定の接続ポイントに追加されるコードです。簡単に言うと、通知は接続ポイントが傍受された後に何を行うかを指します。つまり、通知はアスペクトの特定の実装です。通知は次のように分類されます。前通知、事後通知、例外通知、最終通知、周囲通知;

5. アスペクト

        これは、エントリ ポイントと通知の組み合わせであるシステム機能 (トランザクション処理など) への水平方向の切断をカプセル化するクラスを指します。

6. 織ります

        これは、アスペクト コードをターゲット オブジェクトに挿入してプロキシ オブジェクトを生成するプロセスです。

7. プロキシ

        これは、通知 (拡張) が適用された後、プロキシ オブジェクトが生成されることを意味します。

 11.2.1 Spring AOPの2つのプロキシメソッド

1 つは通常の JDK で、もう 1 つは CGLIB です。

プロキシ オブジェクトが少なくとも 1 つのインターフェイスを実装する場合、デフォルトでは JDK を使用してプロキシ オブジェクトが動的に作成されます。

CGLIB メソッドは、プロキシ オブジェクトがインターフェイスを実装していない場合に使用されます。

インターフェイスが実装されている場合は、スーパークラス インターフェイスを使用してキャストを定義する必要があります

この部分は言葉で明確に説明できることがあまりないので、例を見てください。

11.3 トピックから始めて、最初にパッケージをガイドする

<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>

次に、設定ファイル「applicationContext.xml」を作成します。

<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>

11.4 具体的には3つの方法に分かれる

        11.4.1 最初の方法: オリジナルの SpringAPI インターフェースを使用する

まず、ビジネス インターフェイスと実装クラスを作成します。

public interface UserSerice {
void add();
void delete();
void update();
void select();
}
public class UserServiceImpl implements UserSerice{
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }

    @Override
    public void update() {
        System.out.println("更改了一个用户");
    }

    @Override
    public void select() {
        System.out.println("查询了一个用户");
    }
}

次に、拡張クラス (事前通知と事後通知) があります。

public class BeforeLog implements MethodBeforeAdvice {
    /**
     *
     * @param method 要执行的目标对象的方法
     * @param args 参数
     * @param target 目标对象
     * @throws Throwable
     */
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(method.getClass().getName()+"的"+method.getName()+"被执行了");
    }
}
public class AfterLog implements AfterReturningAdvice {
    /**
     *
     * @param returnValue 返回值
     * @param method
     * @param args
     * @param target
     * @throws Throwable
     */
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,返回的结果为"+returnValue);
    }
}

次に、Spring 設定ファイル「applicationContext.xml」に移動して Bean を登録し、aop カットインの実装を実現します。

<!--    注册bean-->
    <bean id="userService" class="com.gcx.Service.UserServiceImpl"/>
    <bean id="beforeLog" class="com.gcx.log.BeforeLog"/>
    <bean id="afterLog" class="com.gcx.log.AfterLog"/>
    <!--    配置AOP:需要导入aop的约束-->
    <aop:config>
<!--        首先需要一个切入点:expression:表达式,execution(要执行的位置 )-->
<!--        要给com.gcx.Service.UserServiceImpl这个类插入方法,但是这个类有很多方法,所以用.*(..) [两个点代表可以有任意个参数]-->
        <aop:pointcut id="pointcut" expression="execution(* com.gcx.Service.UserServiceImpl.*(..))"/>
<!--    执行环绕增加!-->
        <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>

最終試験。

public class Mytest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserSerice userService = (UserSerice) context.getBean("userService");
        userService.add();
    }

出力結果

java.lang.reflect.Method的add被执行了
增加了一个用户
执行了add方法,返回的结果为null

このことから、コンテンツを追加したい元のコード、つまり拡張コードに実際にコンテンツが追加されていることがわかります。

11.4.2 方法 2  Aop を実装するカスタム クラス

ビジネス実装クラスは変更されず、引き続き userServiceImpl です。

ステップ 1: 独自のカットイン クラスを 1 つ作成する

public class diy {
    public void logBefore(){
        System.out.println("方法执行前");
    }
    public void logAfter(){
        System.out.println("方法执行后");
    }
}

次に、Spring 構成ファイル「applicationContext.xml」に移動して Bean を登録します。 

    <bean id="diy" class="com.gcx.log.diy"/>
    <aop:config>
<!--        声明为切面(aspect)类-->
        <aop:aspect ref="diy">
<!--            切入点-->
            <aop:pointcut id="pointcut" expression="execution(* com.gcx.Service.UserServiceImpl.*(..))"/>
<!--            通知-->
            <aop:before method="logBefore" pointcut-ref="pointcut" />
            <aop:after method="logAfter" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

テスト

    @Test
    public void LogTest(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserSerice userService = context.getBean("userService", UserSerice.class);
        userService.add();
    }

出力結果

方法执行前
增加了一个用户
方法执行后

そうです、カスタマイズしたカットインクラスであっても、出力コードに直接書き込むことができます。

11.4.3 アノテーションを使用する方法 3

ステップ 1: アノテーション実装用の拡張クラスを作成する

/**
 * @Aspect 标注该类是一个切面
 */
@Aspect
public class AnnotationPointCut {
    @Before("execution(* com.gcx.Service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("-----方法执行前-------");
    }
    @After("execution(* com.gcx.Service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("-----方法执行后------");
    }


    /**
     *
     * @param jp 连接点
     */
    //    在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点
    @Around("execution(* com.gcx.Service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("======环绕前=====");
//        执行方法,此句代码的执行就表示切入点方法的执行
        Object o = jp.proceed();
        System.out.println("=====环绕后======");
        System.out.println(o);
    }
}

ステップ 2: Spring 構成ファイルで、Bean を登録し、アノテーションをサポートする構成を追加します。

    <bean id="annotationPointCut" class="com.gcx.log.AnnotationPointCut"/>
<!--    开启注解支持  -->
    <aop:aspectj-autoproxy/>
<!--    Spring代理模式有两种:  1. JDK(默认)  2.CGlib
                               当proxy-target-class为false使用默认JDK;
                               当proxy-target-class为true使用CGlib;
                               -->
<!--    <aop:aspectj-autoproxy proxy-target-class="false"/>-->

テスト

@Test
    public void LogTest(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserSerice userService = context.getBean("userService", UserSerice.class);
        userService.add();
    }

出力結果

======环绕前=====
-----方法执行前-------
增加了一个用户
=====环绕后======
null
-----方法执行后------

11.5 AOP「ハートブリーディング」の概要

ポイントカット宣言式カテゴリ:
    1. ポイントカットは com.gcx.Service.UserServiceImpl() メソッドです。
        <aop:pointcut id="pointcut1"expression="execution(* com.gcx.Service.UserServiceImpl())"/>
    2. ポイントカットは、戻り値がなく空のパラメータを持つ com.gcx.Service クラスのすべてのメソッドです。
        <aop:pointcut id="pointcut2"expression= "execution(void com.gcx.Service.*())" / >
    3. ポイントカットは、戻り値もパラメータの要件も持たない com.gcx.Service クラスのすべてのメソッドです。
        <aop:pointcut id="pointcut3"expression="execution(void com.gcx.Service.* (.. ))"/>
    4. ポイントカットは、戻り値の要件がなく、パラメーターが空である com.gcx.Service クラス内のすべてのメソッドです。
        <aop:pointcut id="pointcut4"expression="execution (* com.gcx.Service. *())"/>
    5. ポイントカットは com.gcx.Service クラスのすべてのメソッドであり、戻り値とパラメーターの要件はありません。
        <aop:pointcut id=pointcut5" 式="実行(* com.gcx.Service.*(..))"/>
    6. ポイントカットは、com.gcx. パッケージ内のすべてのクラスのすべてのメソッドであり、戻り値とパラメーターの要件はありません
        。 *.*(. .))"/>
    7. ポイントカットは、com.gcx パッケージ内のすべてのクラスの UserServiceImpl メソッドです。戻り値とパラメーターの要件はありません。
        <aop:pointcut id="pointcutbag6" 式="execution(* com.gcx .*.UserServiceImpl(..))"/>
    8. すべてのクラスのすべてのメソッドについて、戻り値とパラメータの要件はありません。        
        <aop:pointcut id="pointcutbag7"expression="実行(* *(..))"/>

通知戦略と実行順序:
    1. 事前通知 (前): ターゲット メソッドの実行前に実行される通知
    2. 事後通知 (後): ターゲット メソッドの実行後に実行される通知。
    3. スロー後: ターゲット メソッドが例外をスローしたときに実行される通知。
    4. 復帰後: 対象メソッドが正常に実行されたことを通知します。
    5. サラウンド通知 (around): ターゲット メソッドの実行の前後に追加のコードを実行できるという通知
    <!--通知の実行順序は、xml ファイルで設定された順序に関連しています -->
        //通知を囲むメソッドは次の定義規則に従う必要があります。    
        //1: ProceedingJoinPoint 型のパラメーターが必要です。     //2         :
        戻り値が Object 型である必要があります。    
        //3: Object v = point.proceed() を実行します。 /4の前後の拡張ビジネス ロジック間    
: メソッドは最後に return v を返します;
    例: public Object method5(ProceedingJoinPoint point) throws Throwable {                System.out.println("~~~~~~~~~~~~) ~ 前に通知を囲みます ~~~~~~ ~~~~~");

    //point.proceed (args) は実行要求メソッドを示します。このメソッドの前はポイントのカット前を示し、このメソッドの後はカット後のポイントを示します。この文の実行はポイントの実行を意味します-cut メソッド. Object v = point.proceed
    ( );
    System.out.println("~~~~~~~~~~~~ サラウンド通知 after~~~~~~~~~~~~~~" );
    v を返します;
    } 

 通知ルールの概要:
    XML 構成を使用すると、通知の実行順序は構成の順序に関連します。
    1. 事前通知、事後通知、最終通知を利用する
        1.1 異常事前通知なし>エントリポイント方式 → 事後通知と最終通知(実行順序はxml設定の順序で決まります) 1.2 事前
        通知> 例外ありのエントリ ポイント メソッド -> ポスト通知 > 例外通知
    2. サラウンド通知、例外通知
        2.1 例外なし: サラウンド通知プレ > エントリ ポイント メソッド > サラウンド通知ポスト
        2.2 例外あり: サラウンド通知プレ > エントリ ポイント メソッド > 例外通知
    3すべての通知を使用する:
        3.1 例外なし: 実行シーケンスは次のとおりです:
            3.1.1 事前アドバイスおよび事前サラウンド通知 (XML 構成順序に従って)
            3.1.2 エントリ ポイント メソッド
            3.1.3 事後通知、最終通知、サラウンド通知事後位置(xmlの設定順序により実行の場合は2通りあります。1つはフロントかサラウンドのどちらかが存在する場合、もう1つは途中に他の設定がなくフロントとサラウンドの両方が存在する場合です。) 3.2例外は例外です。実行シーケンスは次のとおりです。 3.2.1 事前
        通知             3.2.2 エントリ ポイント方式
            3.2.3             事後通知、例外通知 (実行シーケンスは上記と同じ)     要約: 間に他の設定項目がない場合フロントとサラウンド、ポスト、例外、最終的な実行順序は構成と同じです


12. 宣言的トランザクション 

1. トランザクションは、データの「一貫性」の問題を伴うプロジェクト開発プロセスにおいて非常に重要です。
2. トランザクション管理は、データの整合性と一貫性を確保するためのエンタープライズ レベルのアプリケーション開発において不可欠なテクノロジです。
3. トランザクションは、一連のアクションを独立した作業単位として扱うもので、これらのアクションはすべて完了するか、すべてが機能しません。

 12.1 トランザクションの 4 つの属性

1. 原子性: トランザクションは、一連のアクションで構成される原子的な操作です。トランザクションの原子性により、アクションが完了するか、まったく完了しないことが保証されます。 2. 一貫性: すべてのトランザクション アクションが完了すると、トランザクションはコミットされます
。 。データとリソースはビジネス ルールを満たす一貫した状態にあります。
3. 分離: 複数のトランザクションが同じデータを同時に処理する可能性があるため、データの破損を防ぐために各トランザクションを他のトランザクションから分離する必要があります。 4. 永続性:
トランザクションが完了すると、 、システム内でどのようなエラーが発生しても、結果には影響しません。通常、トランザクション結果は永続ストレージに書き込まれます。

12.2 Spring のトランザクション管理 

Spring は、プログラムによるトランザクション管理と宣言的なトランザクション管理をサポートしています。
1. 宣言型トランザクション AOP:
一般に、プログラムによるトランザクションよりも使いやすいです。
トランザクション管理コードをビジネス メソッドから分離し、宣言的な方法でトランザクション管理を実装します。
トランザクション管理を横断的な問題として捉え、AOP メソッドを通じてモジュール化します。Spring は、Spring AOP フレームワークを通じて宣言型トランザクション管理をサポートします。
2. プログラムによるトランザクション: コードでトランザクションを管理する必要がある:
トランザクション管理コードをビジネス メソッドに埋め込んで、トランザクションのコミットとロールバックを制御する
欠点: 各トランザクション操作のビジネス ロジックに追加のトランザクション管理コードを含める必要がある

12.2.1 トランザクションマネージャー 

Spring がどのトランザクション管理戦略 (プログラム的または宣言的) を使用する場合でも、トランザクション マネージャーが必要です。
これは、テクノロジーに依存しない一連のメソッドをカプセル化する、Spring の中核となるトランザクション管理の抽象化です。

12.3 Spring トランザクション伝播機能 

トランザクションの伝播動作は、複数のトランザクション メソッドが相互に呼び出したときに、トランザクションがどのようにそれらの間で伝播するかを示します。Spring は 7 種類のトランザクション伝播動作をサポートしています。
1.propagation_requierd: 現在トランザクションがない場合は新しいトランザクションを作成し、すでにトランザクションがある場合はこのトランザクションに参加します。これが最も一般的な選択です。
2.propagation_supports: 現在のトランザクションをサポートします。現在のトランザクションがない場合、非トランザクション メソッドで実行されます。
3.propagation_mandatory: 現在のトランザクションを使用します。現在のトランザクションがない場合、例外がスローされます。
4.propagation_required_new: 新しいトランザクションを作成します。現在のトランザクションがある場合は、現在のトランザクションを一時停止します。
5.propagation_not_supported: 非トランザクション方式で操作を実行します。現在のトランザクションがある場合は、現在のトランザクションを一時停止します。
6.propagation_never: 非トランザクション方式で操作を実行し、現在のトランザクションが存在する場合は例外をスローします。
7.propagation_nested: トランザクションが現在存在する場合は、ネストされたトランザクション内で実行します。現在のトランザクションがない場合は、propagation_required と同様の操作を実行します。Spring
のデフォルトのトランザクション伝播動作は PROPAGATION_REQUIRED であり、ほとんどの場合に適しています。

12.4 ヘッダー ファイルの制限付きインポート 

xmlns:tx="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">

12.5 ケース 

エンティティクラス (コンストラクターインジェクションを記述したいため、空のパラメーターとパラメーター化された構築メソッドを設定する必要があります)

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private int pwd;
}

ユーザーマッパー

public interface UserMapper {
//    查询全部用户信息
    List<User> selectUser();
//    添加一个用户
    int addUser(User user);
//    根据id删除一个用户
    int deleteUser(int id);
}

UserMapper.xml (SQL ステートメントを記述する)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gcx.mapper.UserMapper">
    <select id="selectUser" resultType="user">
        select *from user;
    </select>
    <insert id="addUser" parameterType="user">
        insert into user (id,name,pwd) values(#{id},#{name},#{pwd})
    </insert>
    <delete id="deleteUser" parameterType="int">
        delete from user where id = #{id}
    </delete>

</mapper>

mybatis-config.xml (マッパー設定ファイル)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--核心配置文件-->
<configuration>
<!--别名管理-->
    <typeAliases>
        <package name="com.gcx.pojo"/>
    </typeAliases>
//使用Spring绑定配置文件,省略配置mapper命名空间
</configuration>

spring-dao.xml

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--DataSource:使用Spring的数据源替换Mybatis的配置  c3p0 dbcp druid
这里使用Spring提供的jdbc:org.springframework.jdbc.datasource-->
    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>


    <!--    配置sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="datasource"/>
<!--    绑定Mybatis配置文件-->
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
    <property name="mapperLocations" value="classpath:com/gcx/mapper/*.xml"/>
</bean>
<!--   SqlSessionTemplate:就是我们使用的SqlSession -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--    只能使用构造器注入SqlSessionFactory,因为没有set方法-->
    <constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
    <!--    配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
    </bean>
    <!--    结合AOP,实现事务的置入-->
    <!--    配置事务通知:-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--        给那些方法配置事务:-->
        <tx:attributes>
            <!--            配置事务的传播特性:propagation 默认为 REQUIRED-->
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="delete" propagation="REQUIRED"/>
            <tx:method name="update" propagation="REQUIRED"/>
            <!--            read-only:只读-->
            <tx:method name="query" read-only="true"/>
            <!--            配置所有方法-->
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <!--    配置事务切入-->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.gcx.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

  applicationContext.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">
    <import resource="spring-dao.xml"/>
    <bean id="userMapper" class="com.gcx.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>
</beans>

UserMapperImpl (実装クラス)

/**
 * 另一种写法,直接继承SqlSessionDaoSupport;
 * public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{}
 * 该方法内部已经写好了构造SqlSessionTemplate类型的变量sqlSession,并创建了SqlSessionFactory工厂
 */
public class UserMapperImpl implements UserMapper{
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }
    public List<User> selectUser() {
        User user = new User(7, "小孟", 123134);
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.addUser(user);
        mapper.deleteUser(6);
        return mapper.selectUser();
    }


    public int addUser(User user) {
        return sqlSession.getMapper(UserMapper.class).addUser(user);
    }

    public int deleteUser(int id) {
        return sqlSession.getMapper(UserMapper.class).deleteUser(id);
    }
}

テストテスト

public class Mytest {
    @Test
    public void test(){
        ApplicationContext Context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = Context.getBean("userMapper", UserMapper.class);
        List<User> users = userMapper.selectUser();

        for (User user : users) {
            System.out.println(user);

        }
    }
}

 出力結果

User(id=1, name=小顾, pwd=123456)
User(id=2, name=小董, pwd=123666)
User(id=3, name=小杨, pwd=1234567)
User(id=4, name=小孟, pwd=1234567)
User(id=5, name=小鑫, pwd=122223)
User(id=7, name=小孟, pwd=123134)

13. 定期的な自己要約

約 2 週間の独習を経て、Spring が何であるかを理解しました。面接の 2 つの主要なポイント「IOC 制御の反転」と「AOP アスペクト プログラミング」の学習はさらに難しく、Spring の設定ファイルを理解しました。その中で、何に使われるのか、複数の Bean インジェクション方法、Spring を使ってデータベースに自動的に接続する方法、JDBC ほど面倒なものである必要はない、2 つの異なるプロキシ モード、コード拡張を実装するためのさまざまな AOP メソッド、さまざまな通知、宣言的なトランザクション。

最も幸運だったのは、これらのコードを作成する過程で多くの問題に遭遇し、多くのエラーが報告されたことですが、それでも諦めず、さまざまな Baidu と csdn が問題の解決策を探してくれたことです。進歩があるでしょう!

おすすめ

転載: blog.csdn.net/m0_74135466/article/details/128227021