Spring框架學習筆記詳細

1.Spring

寫在前面:歡迎來到「發奮的小張」的博客。我是小張,一名普通的在校大學生。在學習之餘,用博客來記錄我學習過程中的點點滴滴,也希望我的博客能夠更給同樣熱愛學習熱愛技術的你們帶來收穫!希望大家多多關照,我們一起成長一起進步。也希望大家多多支持我鴨,喜歡我就給我一個關注吧!

1.簡介

  • Spring:春天---->給軟件行業帶來了春天
  • 2002,首次退出了Spring框架的雛形:interface21框架!
  • Spring框架即以interface21框架爲基礎,經過重新設計,並不斷豐富其內涵,於2004年3月24日,發佈了1.0正式版。
  • Rod Johnson,Spring Framework創始人,著名作者。很難想象Rod Johnson的學歷,真的讓好多人大喫一驚,他是悉尼大學的博士,然而他的專業不是計算機,而是音樂學。
  • Spring理念:使現有的技術更加容易使用,本身是一個複雜的綜合性框架。
  • SSH:Struct2+Spring+Hibernate!
  • SSM:SpringMVC+Spring+Mybatis!

官方文檔:https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/core.html#spring-core

官網: https://spring.io/projects/spring-framework#overview
官方下載地址: http://repo.spring.io/release/org/springframework/spring
GitHub: https://github.com/spring-projects/spring-framework

2.優點

  • Spring是一個開源的免費的框架(容器)。
  • Spring是一個輕量級的、非入侵式的框架!
  • IOC控制反轉,AOP面向切面編程。
  • 支持事務的處理,對框架的整合支持!

總結一句話:Spring就是一個輕量級的IOC(控制反轉),AOP(面向切面編程)的框架!

3.組成

在這裏插入圖片描述

4.拓展

在這裏插入圖片描述

  • Spring Boot

    • 一個快速開發的腳手架
    • 基於SpringBoot可以快速的開發單個微服務
    • 約定大於配置!
  • Spring Cloud

    • SpringCloud是基於SpringBoot實現的

    因爲現在大多數公司都在使用SpringBoot進行開發,學習SpringBoot的前提,掌握Spring,及SpringMVC!承上啓下的作用!

弊端:發展太久,違背了原來的理念。配置十分繁瑣,人稱:“配置地獄”

2.IOC理論推導

  1. UserDao接口
  2. UserDaoImpl實現類
  3. UserService業務接口
  4. UserServiceImpl業務實現類

在我們之前的業務中,用戶的需求可能會影響原來代碼。我們需要根據用戶需求修改原代碼。如果程序代碼量十分大,修改一次的成本十分昂貴!

我們使用一個set接口實現。已經發生了革命性得變革!

    private UserDao userDao;

    //利用set實現動態值得注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public static void main(String[] args) {

        UserService service = new UserServiceImpl();

        ((UserServiceImpl)service).setUserDao(new UserOracleImpl());

        service.getUser();
    }
  • 之前程序是主動創建對象!控制權在程序員手上!
  • 使用了set注入後,程序不再具有主動性,變成了被動接受對象!

這種思想從本質上解決了問題,我們不需要管理對象的創建,耦合性大大降低,可以專注在業務實現上!這就是IOC原型!

在這裏插入圖片描述
在這裏插入圖片描述

3.I0C本質

控制反轉loC(Inversion of Control),是-種設計思想,DI(依賴注入)是實現IoC的-種方法,也有人認爲DI只是IoC的另一種說法。沒有IoC的程序中,我們使用面向對象編程, 對象的創建與對象間的依賴關係完全硬編碼在程序中,對象的創建由程序自己控制,控制反轉後將對象的創建轉移給第三方,個人認爲所謂控制反轉就是:獲得依賴對象的方式反轉了。

採用XML方式配置Bean的時候,Bean的定義信息是和實現分離的,而採用註解的方式可以把兩者合爲一體,Bean的定義信息直接以註解的形式定義在實現類中,從而達到了零配置的目的。

控制反轉是一種通過描述(XML或註解)並通過第三方去生產或獲取特定對象的方式。在Spring中實現控制反
轉的是IoC容器,其實現方法是依賴注入(Dependency Injection,DI)。

4.第一個HelloSpring程序

環境:

  • idea集成工具
  • Maven倉庫

搭建步驟:

  • 新建一個空白的Maven工程

在這裏插入圖片描述

接着自定義一個groupid和artifactid

在這裏插入圖片描述

點擊下一步就創建完成

在這裏插入圖片描述

此時的項目結構爲下圖:

在這裏插入圖片描述

  1. Maven依賴文件

    配置pom.xml:

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
    
    <!--https://mvnrepository.com/artifact/org. springframework/spring-webmvc-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
    
  2. 編寫實現類

    package com.zhang.pojo;
    
    public class Hello {
        private String str;
    
        public String getStr() {
            return str;
        }
    
        public void setStr(String str) {
            this.str = str;
        }
    
        @Override
        public String toString() {
            return "Hello{" +
                    "str='" + str + '\'' +
                    '}';
        }
    }
    
    
  3. 配置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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
            <!--使用Spring來創建對象,在Spring這些都稱爲Bean
            bean=對象  new Hello()
            類型  變量名 = new 類型()
            id = 變量名
            class = new 的對象
            property  相當於給對象屬性設值
            -->
            <bean id="hello" class="com.zhang.pojo.Hello">
                <property name="str" value="Spring"/>
            </bean>
    
    
    </beans>
    

    此時的項目結構爲下圖:

在這裏插入圖片描述

  1. 測試

        public static void main(String[] args) {
            //獲取Spring的上下文對象
            ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
            //我們的對象現在都在Spring中管理,要使用,直接取出來
    
            Hello hello = (Hello) context.getBean("hello");
    
            System.out.println(hello);
        }
    

思考問題?

●Hello對象是誰創建的?
hello對象是由Spring創建的
●Hello 對象的屬性是怎麼設置的?
hello對象的屬性是由Spring容器設置的,

這個過程就叫控制反轉:
**控制:**誰來控制對象的創建,傳統應用程序的對象是由程序本身控制創建的,使用Spring後,對象是由Spring來創
建的.

**反轉:**程序本身不創建對象,而變成被動的接收對象.

**依賴注入:**就是利用set方法來進行注入的.

**I0C是一種編程思想,**由主動的編程變成被動的接收.可以通過newClassPathXmlApplicationContext去瀏覽一下底層源碼 .

OK ,到了現在,我們徹底不用再程序中去改動了,要實現不同的操作,只需要在xml配置文件中進行修改,所謂的
IoC,-句話搞定:對象由Spring來創建,管理, 裝配!

5.IOC創建對象的方式

在獲取容器的時候就已經將配置文件beans.xml中的bean註冊對象創建完畢

 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
  1. 使用無參構造創建對象,默認實現

  2. 假設我們要是有有參構造實現

    1. 下標賦值

          <!--有參構造方法
              1.下標賦值
          -->
          <bean id="user" class="com.zhang.pojo.User">
              <constructor-arg index="0" value="這是一個姓名"/>
          </bean>
      
    2. 參數類型

          <!--2.通過參數類型創建有參構造
          不建議使用
          -->
          <bean id="user" class="com.zhang.pojo.User">
              <constructor-arg type="java.lang.String" value="這是一個名字"/>
          </bean>
      
    3. 參數名類型(掌握)

          <!--3.通過參數名創建有參構造-->
          <bean id="user" class="com.zhang.pojo.User">
              <constructor-arg name="name" value="ahah"/>
          </bean>
      

6.Spring配置

6.1別名

   <!--別名,如果添加了別名,我們可以使用別名獲取這個對象
        注意:原id仍然有效
    -->
    <alias name="user" alias="user2"/>

6.2Bean的配置

    <!--
    id : bean 的唯一標識,相當於對象名
    class : bean 對象所對應的全限定名 : 包名 + 類名
    name : 也是別名,而且name 可以同時取多個別名
    -->
    <bean id="user1" class="com.zhang.pojo.User" name="user3,u1">
        <constructor-arg name="name" value="sss"/>
    </bean>

6.3import

這個import,一般用於團隊開發使用,它可以將多個配置文件合併爲一個。

假設現在項目有多個人開發,這三個人負責不同的類開發。不同的類需要註冊在不同的beans中。我們可以用import將所有人的beans.xml合併爲一個總的。

使用時直接使用總的配置!

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

    <import resource="beans.xml"/>
    <import resource="beans1.xml"/>

</beans>

此時的配置文件如下如:
在這裏插入圖片描述

7.DI依賴注入

7.1構造器注入

前面p5已經說了

###7.2Set方式注入【重點】

  • 依賴注入:Set注入!

    • 依賴:bean對象的創建依賴於容器
    • 注入:bean對象中的所有屬性由容器來注入

    【環境搭建】

    1.複雜類型

public class Address {
private String address;

  public String getAddress() {
      return address;
  }

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

}




2.真實測試對象

```java
public class Student {

    private String name;

    private Address address;

    private String[] book;

    private List<String> hobbys;

    private Map<String,String> card;

    private Set<String> games;

    private String wife;

    private Properties info;
}

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


    <bean id="student" class="com.zhang.pojo.Student">
        <!--方式一:普通值注入,value-->
        <property name="name" value="晶瑩"/>
    </bean>


</beans>

4.測試類

public class MyTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        Student student = (Student) context.getBean("student");

        System.out.println(student);
    }
}

完善注入信息

   <bean id="address" class="com.zhang.pojo.Address">
        <property name="address" value="武漢"/>
    </bean>
    <bean id="student" class="com.zhang.pojo.Student">
        <!--方式一:普通值注入,value-->
        <property name="name" value="晶瑩"/>
        <!-- 第二種: Bean注入,value -->
        <property name="address" ref="address"/>
        <!-- 數組注入 ref -->
        <property name="book">
            <array>
                <value>紅樓夢</value>
                <value>西遊記</value>
                <value>水滸傳</value>
                <value>三國演義</value>
            </array>
        </property>
        <!-- list注入 ref -->
        <property name="hobbys">
            <list>
                <value>聽歌</value>
                <value>編程</value>
                <value>看劇</value>
            </list>
        </property>
        <!-- Map注入 ref -->
        <property name="card">
            <map>
                <entry key="身份徵" value="123456789012345678"/>
                <entry key="銀行卡" value="123456789012345678"/>
            </map>
        </property>
        <!-- Set注入 -->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>CF</value>
            </set>
        </property>
        <!-- null值注入 -->
        <property name="wife">
            <null></null>
        </property>
        <!-- Properties注入 -->
        <property name="info">
            <props>
                <prop key="driver">mysql</prop>
                <prop key="url">http:/sss</prop>
                <prop key="username">root</prop>
                <prop key="password">root</prop>
            </props>
        </property>
    </bean>

7.3拓展方式注入

我們可以使用p命名空間,或者是c命名空間進行注入

官方解釋如下圖:

在這裏插入圖片描述

在這裏插入圖片描述

使用c或者p命名空間,需要先導兩個標籤

p和c的命名空間標籤約束

      xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"

使用

<?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: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">

    <!-- p命名空間注入 可以直接注入屬性的值 -->
    <bean id="user" class="com.zhang.pojo.User" p:name="哈哈" p:age="16"/>

    <!-- c命名空間注入, 可以通過構造器注入 construct-args-->
    <bean id="user2" class="com.zhang.pojo.User" c:age="18" c:name="弟弟"/>

</beans>

測試:

    @Test
    public void test2(){
        ApplicationContext context = new  ClassPathXmlApplicationContext("userbeans.xml");

        User user = context.getBean("user2", User.class);

        System.out.println(user);
    }

注意點:p和c命名空間不能直接使用,需要導入xml約束

7.4bean的作用域

官方原文:
在這裏插入圖片描述

翻譯後:

在這裏插入圖片描述

1.單例模式(spring默認機制)

每次從容器中取出bean,都是同一個對象

 <bean id="user2" class="com.zhang.pojo.User" c:age="18" c:name="弟弟" scope="singleton"/>

2.原型模式

每次從容器中取出bean,都是一個新的對象

    <bean id="user2" class="com.zhang.pojo.User" c:age="18" c:name="弟弟" scope="prototype"/>

3.其餘request,session,application,只能在web開發中使用!

8.bean的自動裝配

  • 自動裝配是Spring滿足bean依賴的一種方式!
  • Spring會在上下文中自動尋找,並自動給bean裝配屬性!

在Spring中有三種自動裝配的方式

  1. 在xml中顯示配置
  2. 在Java中顯示配置
  3. 隱式 的自動裝配bean【重要】

8.1測試

ByName自動裝配

    <!--
     byName : 會自動在容器上下文中查找,有沒有和id對應的set方法
     -->
    <bean id="people" class="com.zhang.pojo.People" autowire="byName">
        <property name="name" value="大俠"/>
    </bean>

ByType自動裝配

    <bean id="cat" class="com.zhang.pojo.Cat"/>
    <bean id="dog11" class="com.zhang.pojo.Dog"/>
    <!--
     byName : 會自動在容器上下文中查找,有沒有和id對應方法的bean
     byType : 會自動在容器上下文中查找,有沒有和class類型對應的bean
     -->
    <bean id="people" class="com.zhang.pojo.People" autowire="byType">
        <property name="name" value="大俠"/>
    </bean>

小結:byname的時候,需要保證所有的bean的id唯一,並且這個bean需要和自動注入的屬性的set方法一致!

bytype的時候,需要保證所有的bean的class唯一,並且這個bean需要和自動注入的屬性類型一致!

8.2使用註解自動裝配

jdk1.5支持註解,Spring2.5就支持註解!

要使用註解須知:

  1. 導入約束:

xmlns:context=“http://www.springframework.org/schema/context”

  1. 配置註解的支持:

<context:annotation-config/>
<?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/>

</beans>

@Autowried

直接在屬性上使用即可!也可以在set方式上使用!

使用Autowried我們可以不用編寫set方法,前提是你這個自動裝配的屬性在IOC容器中存在且符合名字byname!

科普:

@Nullable  字段標記了這個註解,說明這個字段可以爲null

測試代碼:

    //如果顯示定義了Autowried的required屬性爲false,說明這個對象可以爲null,否則不允許爲空
    @Autowired(required = false)
    private Cat cat;
    @Autowired
    private Dog dog;

如果@Autowired自動裝配的環境比較複雜,自動裝配無法通過一個註解【@Autowired】完成時,我們可以使用@Qualifier(value = “xxx”)p配合@Autowired使用,指定唯一的bean注入!

    @Autowired
    @Qualifier(value = "cat22")
    private Cat cat;
    @Autowired
    @Qualifier(value = "dog22")
    private Dog dog;
    private String name;

    <bean id="cat" class="com.zhang.pojo.Cat"/>
    <bean id="cat22" class="com.zhang.pojo.Cat"/>
    <bean id="dog" class="com.zhang.pojo.Dog"/>
    <bean id="dog22" class="com.zhang.pojo.Dog"/>
    <bean id="people" class="com.zhang.pojo.People"/>

@Resource註解

public class People {

    @Resource(name = "cat22")
    private Cat cat;
    @Resource
    private Dog dog;

小結:

@Autowried和**@Resource註解**的區別:

  • 都是自動裝配使用

  • @Autowried通過bytype方式實現【常用】

  • @Resource默認通過byname方式,如果找不到就通過bytype,如果都找不到,就報錯!【常用】

9.使用註解開發

在Spring4之後,要使用註解開發,必須要保證aop包導入!
在idea右上角查看自己的maven倉庫,看看依賴是否導入!
在這裏插入圖片描述
使用註解需要導入context約束,增加註解支持!

<?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/>

</beans>

1.bean

2.屬性如何注入

//等價於 <bean id="user" class="com.zhang.pojo.User"/>
//@Component  組件 裝配的id爲類名小寫
@Component
public class User {

    //相當於<property name = "name" value="哈哈哈哈"/>
    @Value("哈哈哈哈")
    public String name;
}

//等價於 <bean id="user" class="com.zhang.pojo.User"/>
//@Component  組件
@Component
public class User {

    //相當於<property name = "name" value="哈哈哈哈"/>
//    @Value("哈哈哈哈")
    public String name;
    
    //相當於<property name = "name" value="哈哈哈哈"/>
    @Value("哈哈哈哈")
    public void setName(String name) {
        this.name = name;
    }
}

​ 測試:

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = context.getBean("user", User.class);
        System.out.println(user.name);
    }

3.衍生的註解

@Component有幾個衍生註解(下面三個註解功能和@Component一樣),在web開發中,會按照mvc三層架構分層。

dao【@Repository】

service【@Service】

controller【@Controller】

@Component,@Repository,@Service,@Controller這四個註解功能一樣,都是將某個類註冊到spring,裝配到bean中

4.自動裝配

-@Autowired :自動裝配,通過類型,名字
    如果Autowired不能唯一自動裝配,我們可以使用@Qualifier(value = "xxx")p配合@Autowired使用,指定唯一的bean注入!
-@Resource : 自動裝配,通過名字,類型
-@Nullable 字段標記了這個註解,說明這個字段可以爲null

5.作用域

單例

@Component
@Scope("singleton")//單例
public class User {

}

6.小結

xml與註解:

​ xml更萬能,使用任何場合

​ 註解不是自己的類使用不了,維護相對複雜!

xml與註解的最佳實踐:

​ xml用來管理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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 指定要掃描的包,這個包下的註解就會生效 -->
    <context:component-scan base-package="com.zhang"/>
    
    <!-- 開啓註解支持 -->
    <context:annotation-config/>

</beans>

10.使用java的方式配置Spring

我們現在要完全不使用Spring的xml配置,全權交給java來做

JavaConfig是Spring的一個子項目,Spring4之後,他成爲了一個核心功能!

在這裏插入圖片描述

配置類

package com.zhang.config;

import com.zhang.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

//這是一個配置類,和beans.xml一樣
//他會被註冊到spring容器中,他本來也是一個Component
@Configuration
@ComponentScan("com.zhang.pojo")
@Import(ZhangConfig2.class)
public class ZhangConfig {

    //註冊一個bean,就相當於之前寫的一個bean標籤
    //這個方法的名字,就相當於bean標籤中的id
    @Bean
    public User user(){
        return new User();//返回要注入的對象
    }
}

實體類

package com.zhang.pojo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;

//註解,說明這個類被spring註冊到容器中
@Component
public class User {

    private String name;

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

    public String getName() {
        return name;
    }

    @Value("王老五")
    public void setName(String name) {
        this.name = name;
    }
}

測試類

public class MyTest {
    public static void main(String[] args) {
        //如果完全使用了配置類方式,我們就只能通過AnnotationConfigApplicationContext上下文來獲取容器,通過class類加載
        ApplicationContext context = new AnnotationConfigApplicationContext(ZhangConfig.class);

        User user = (User) context.getBean("user");

        System.out.println(user);

    }
}

這種純java的配置方式,在SpringBoot中隨處可見!

11.代理模式

爲什麼要學代理模式?

因爲這就是springAOP的底層!【SpringAOP】【SpringMVC】

代理模式分類

  • 靜態代理
  • 動態代理

在這裏插入圖片描述

11.1靜態代理

角色分析:

  • 抽象角色:一般會使用接口或着抽象類實現
  • 真實角色:被代理的角色
  • 代理角色:代理真實角色,代理後一般會做一些附屬操作
  • 客戶:訪問代理對象的人

代碼步驟:

1.接口


//租房
public interface Rent {

    public void rent();
}

2.真實角色

//房東
public class Host implements Rent {
    @Override
    public void rent() {
        System.out.println("房東要出租房!");
    }
}

3.代理角色

public class Proxy implements Rent {
    private Host host;

    public Proxy() {
    }

    public Proxy(Host host) {
        this.host = host;
    }


    @Override
    public void rent() {
        setHouse();
        host.rent();
        hetong();
        fare();
    }

    public void setHouse(){
        System.out.println("中介帶你看房!");
    }

    public void fare(){
        System.out.println("收中介費!");
    }
    public void hetong(){
        System.out.println("籤租賃合同");
    }
}

4.客戶端訪問代理角色

ic class Cilent {
    public static void main(String[] args) {
        Host host=new Host();
        host.rent();
        //代理,代理一半會有一些附屬操作
        Proxy proxy = new Proxy(host);
        proxy.rent();
    }

代理模式好處:

  • 可以是真實角色的操作更加存粹。不再關注公共的業務
  • 公共業務就交給了代理,實現業務分工
  • 公共業務發生擴展的時候。方便集中管理!

缺點:

一個真實角色產生一個代理角色,類爆炸!

聊聊aop:面向切面編程

在這裏插入圖片描述

11.2動態代理

動態代理和靜態代理角色一樣

動態代理的類是動態生成的,不是我們直接寫好的

動態代理分爲兩大類:基於接口的動態代理,基於類的動態代理

  • 基於接口:JDK動態代理【我們在這裏使用這個】
  • 基於類:cglib
  • java字節碼實現:javasist

需要了解兩個類:Proxy:代理,InvocationHandler:調用處理

動態代理的模板:

package com.zhang.demo04;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//我們用這個類生成代理
public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    //生成得到代理類
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    //處理代理實例並返回結果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //動態代理的本質,就是使用反射
        Object result = method.invoke(target, args);
        return result;
    }
}

測試:

public class Client {

    public static void main(String[] args) {
        //真實角色
        UserServiceImpl service = new UserServiceImpl();
        //代理角色,不存在
        ProxyInvocationHandler pih = new ProxyInvocationHandler();

        //設置代理對象
        pih.setTarget(service);
        //動態生成獲取代理角色
        UserService proxy = (UserService) pih.getProxy();

        proxy.add();
    }

}

動態代理好處:

  • 可以是真實角色的操作更加存粹。不再關注公共的業務
  • 公共業務就交給了代理,實現業務分工
  • 公共業務發生擴展的時候。方便集中管理!
  • 一個動態代理類代理的是一個接口,一般對應一類業務!
  • 一個動態代理類可以代理多個類,只要實現了接口!

12.AOP

12.1什麼是AOP

AOP (Aspect Oriented Programming)意爲:面向切面編程,通過預編譯方式和運行期動態代理實現程序功能
的統- -維護的一種技術。AOP是0OP的延續, 是軟件開發中的一個熱點,也是Spring框架中的一個重要內容,是
函數式編程的一種衍生範型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合
度降低,提高程序的可重用性,同時提高了開發的效率。

在這裏插入圖片描述

12.2Aop在spring中的作用

提供聲明式事務;允許用戶自定義切面
●橫切關注點:跨越應用程序多個模塊的方法或功能。即是,與我們業務邏輯無關的,但是我們需要關注的部分,就是橫切關注點。如日誌,安全,緩存,事務等等…

●切面(ASPECT) :橫切關注點被模塊化的特殊對象。即,它是一一個類。

●通知(Advice) :切面必須要完成的工作。即,它是類中的一一個方法。
●目標(Target) :被通知對象。

●代理(Proxy) :向目標對象應用通知之後創建的對象。

●切入點(PointCut) :切面通知執行的“地點”的定義。

●連接點UointPoint) :與切入點匹配的執行點。

在這裏插入圖片描述
在這裏插入圖片描述

12.3使用Spring實現Aop

【重點】使用AOP織入,需要導入一個包到pom.xml中

<!-- https://mvnrepository.com/artifact/org. aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>

方式一:使用spring的api接口

配置:

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

    <bean id="userservice" class="com.zhang.service.UserServiceImpl"/>
    <bean id="log1" class="com.zhang.log.AfterLog"/>
    <bean id="log" class="com.zhang.log.Log"/>

    <!--使用原生的spring api接口-->
    <!-- 配置aop 需要導入約束-->
    <aop:config>
        <!-- 需要切入點 :expression表達式  execution要執行的位置-->
        <aop:pointcut id="pointcut" expression="execution(* com.zhang.service.UserServiceImpl.*(..))"/>
        <!--執行環繞增強-->
        <aop:advisor advice-ref="log1" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

測試類

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        //動態代理的是接口
        UserService userservice = (UserService) context.getBean("userservice");

        userservice.add();

    }

方法二:使用自定義類

public class DiyPointCut {

    public void before(){
        System.out.println("--------方法執行前-------");
    }

    public void after(){
        System.out.println("-------方法執行後--------");
    }

}
    <!--方式二:自定義類-->
    <bean id="diy" class="com.zhang.diy.DiyPointCut"/>
    <aop:config>
        <!--自定義切面 ref引用的類-->
        <aop:aspect ref="diy">
            <!--切入點-->
            <aop:pointcut id="point" expression="execution(* com.zhang.service.UserServiceImpl.*(..))"/>
            <!--通知-->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>

方式三:使用註解實現

配置

    <!--方式三:使用註解-->
    <bean id="annotationPointcut" class="com.zhang.diy.AnnotationPointcut"/>
    <!--開啓註解支持-->
    <aop:aspectj-autoproxy/>

java類

//使用註解方式實現aop
@Aspect//標註切面類
public class AnnotationPointcut {
    @Before("execution(* com.zhang.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("方法執行前-----------------");
    }

    @After("execution(* com.zhang.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("方法執行後-------------");
    }

    /**
     * 在環繞增強中,我們可以給定一個參數,代表我們要獲取處理的切入點
     */
    @Around("execution(* com.zhang.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("環繞前");

        Object proceed = jp.proceed();

        System.out.println("環繞後");
    }
}

13.整合Mybatis

步驟:

1.導入相關jar包

  • junit
  • mybatis
  • mysql數據庫
  • spring相關
  • aop織入
  • mybatis-spring【新知識】

pom.xml依賴:

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <!--連接spring操作數據庫,還要一個spring-jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <!--aop織入-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
        <!--mybatis-spring整合包-->
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.2</version>
        </dependency>
    </dependencies>

2.編寫配置文件

3.測試

13.1回憶mybatis

1.編寫實體類

2.編寫核心配置文件

3.編寫接口

4.編寫Mapper.xml

5.測試

13.2Mybatis-spring

1.編寫數據源配置

2.sqlSessionFactory

3.sqlSessionTemplate

4.需要給接口加實現類

5.將自己寫的實現類,註冊到spring中

6.測試使用

結構:

spring-dao:

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

        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
        </bean>

        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource"/>
            <property name="configLocation" value="classpath:mybatis-config.xml"/>
            <property name="mapperLocations" value="classpath:com/zhang/mapper/*.xml"/>
        </bean>

        <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
            <constructor-arg index="0" ref="sqlSessionFactory"/>
        </bean>

</beans>

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>

    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <typeAliases>
        <package name="com.zhang.pojo"/>
    </typeAliases>

</configuration>

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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <import resource="spring-dao.xml"/>

    <bean id="userMapper" class="com.zhang.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>

</beans>

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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

        <!--DateSource:使用Spring的數據源替換Mybatis的配置 c3p0 dbcp druid
        我們這裏使用spring提供的JDBC:springframework.jdbc.datasource
        -->

        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
        </bean>

<!--        sqlSessionFactory-->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource"/>
            <!--綁定mybtais配置文件-->
            <property name="configLocation" value="classpath:mybatis-config.xml"/>
            <!--註冊mapper-->
            <property name="mapperLocations" value="classpath:com/zhang/mapper/*.xml"/>
        </bean>

        <!--SqlSessionTemplate就是我們使用的sqlsession-->
        <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
            <!--只能使用構造器注入sqlsessionFactory-->
            <constructor-arg index="0" ref="sqlSessionFactory"/>
        </bean>


        <bean id="userMapper" class="com.zhang.mapper.UserMapperImpl">
            <property name="sqlSession" ref="sqlSession"/>
        </bean>

</beans>

注意:

使用此配置時,需要刪除中文註釋!!

14.聲明式事務

1.回顧事務

  • 把一組業務當成一個業務來做;要麼都成功,要麼都失敗!
  • 事務在項目開發中,十分重要,涉及到數據的一致性問題,不能馬虎!
  • 確保完整性和一致性;

事物的ACID原則:

  • 原子性

  • 一致性

  • 隔離性

    多個業務可能操作同一個資源,防止數據損壞。

  • 持久性

    事務一旦提交我,無論系統發生什麼問題,結果都不會被影響,被持久化到存儲器中!

2.spring的事務管理

  • 聲明式事務 : AOP

    配置聲明式事務:

    <?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"
           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/context
            https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/aop
            https://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/tx
            https://www.springframework.org/schema/tx/spring-tx.xsd">
    
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
        </bean>
    
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource"/>
            <property name="configLocation" value="classpath:mybatis-config.xml"/>
            <property name="mapperLocations" value="classpath:com/zhang/mapper/*.xml"/>
        </bean>
    
        <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
            <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">
            <!--給那些方法配置事務-->
            <!--配置事務的傳播特性: new propagation-->
            <tx:attributes>
                <tx:method name="add" propagation="REQUIRED"/>
                <tx:method name="delete" propagation="REQUIRED"/>
                <tx:method name="update" propagation="REQUIRED"/>
                <tx:method name="query" read-only="true"/>
                <tx:method name="*" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
    
        <!--配置事務切入-->
        <aop:config>
            <!--配置事務切入點-->
            <aop:pointcut id="txPointCut" expression="execution(* com.zhang.mapper.*.*(..))"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
        </aop:config>
    </beans>
    
  • 編程式事務 :需要在代碼中進行事務的管理

思考:

爲什麼需要事務?

  • 如果不配置事務,可能存在數據提交不一致的情況!
  • 如果我們不在spring中去聲明事務,我們需要在代碼中手動配置
  • 事務再項目開發中十分重要,保證了數據的一致性和完整性!

rg.mybatis.spring.SqlSessionFactoryBean">



  <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
      <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">
      <!--給那些方法配置事務-->
      <!--配置事務的傳播特性: new propagation-->
      <tx:attributes>
          <tx:method name="add" propagation="REQUIRED"/>
          <tx:method name="delete" propagation="REQUIRED"/>
          <tx:method name="update" propagation="REQUIRED"/>
          <tx:method name="query" read-only="true"/>
          <tx:method name="*" propagation="REQUIRED"/>
      </tx:attributes>
  </tx:advice>

  <!--配置事務切入-->
  <aop:config>
      <!--配置事務切入點-->
      <aop:pointcut id="txPointCut" expression="execution(* com.zhang.mapper.*.*(..))"/>
      <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
  </aop:config>
```
  • 編程式事務 :需要在代碼中進行事務的管理

思考:

爲什麼需要事務?

  • 如果不配置事務,可能存在數據提交不一致的情況!
  • 如果我們不在spring中去聲明事務,我們需要在代碼中手動配置
  • 事務再項目開發中十分重要,保證了數據的一致性和完整性!

總結:

這是博主學習spring的大致學習流程,如需學習過程的源碼,可私信博主!另附上學習的資源視頻地址:lhttps://www.bilibili.com/video/BV1WE411d7Dv.
如果整理過程中博主有理解不對的地方,歡迎各位小夥伴留言指正,博主一定虛心接受並改正!
如果覺得博主的學習筆記對你有所幫助,可以給博主點一個贊👍

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章