Spring學習筆記(狂神說)

1.Spring

https://www.cnblogs.com/tjlstudy/p/13038508.htmlhtml

學習視頻 : https://space.bilibili.com/95256449java

1.1簡介

Spring : 春天 --->給軟件行業帶來了春天mysql

2002年,Rod Jahnson首次推出了Spring框架雛形interface21框架。git

2004年3月24日,Spring框架以interface21框架爲基礎,通過從新設計,發佈了1.0正式版。程序員

很難想象Rod Johnson的學歷 , 他是悉尼大學的博士,然而他的專業不是計算機,而是音樂學。github

Spring理念 : 使現有技術更加實用 . 自己就是一個大雜燴 , 整合現有的框架技術web

官網 : http://spring.io/spring

官方下載地址 : https://repo.spring.io/libs-release-local/org/springframework/spring/sql

GitHub : https://github.com/spring-projects數據庫

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.5.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.3.RELEASE</version>
</dependency>

1.2優勢

一、Spring是一個開源免費的框架 , 容器 .

二、Spring是一個輕量級的框架 , 非侵入式的 .

三、控制反轉 IoC , 面向切面 Aop

四、對事物的支持 , 對框架的支持

.......

一句話歸納:

Spring是一個輕量級的控制反轉(IoC)和麪向切面(AOP)的容器(框架)。

1.3組成

圖片

Spring 框架是一個分層架構,由 7 個定義良好的模塊組成。Spring 模塊構建在覈心容器之上,核心容器定義了建立、配置和管理 bean 的方式 .

圖片

組成 Spring 框架的每一個模塊(或組件)均可以單獨存在,或者與其餘一個或多個模塊聯合實現。每一個模塊的功能以下:

  • 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要組件是 BeanFactory,它是工廠模式的實現。BeanFactory 使用控制反轉(IOC) 模式將應用程序的配置和依賴性規範與實際的應用程序代碼分開。
  • Spring 上下文:Spring 上下文是一個配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企業服務,例如 JNDI、EJB、電子郵件、國際化、校驗和調度功能。
  • Spring AOP:經過配置管理特性,Spring AOP 模塊直接將面向切面的編程功能 , 集成到了 Spring 框架中。因此,能夠很容易地使 Spring 框架管理任何支持 AOP的對象。Spring AOP 模塊爲基於 Spring 的應用程序中的對象提供了事務管理服務。經過使用 Spring AOP,不用依賴組件,就能夠將聲明性事務管理集成到應用程序中。
  • Spring DAO:JDBC DAO 抽象層提供了有意義的異常層次結構,可用該結構來管理異常處理和不一樣數據庫供應商拋出的錯誤消息。異常層次結構簡化了錯誤處理,而且極大地下降了須要編寫的異常代碼數量(例如打開和關閉鏈接)。Spring DAO 的面向 JDBC 的異常聽從通用的 DAO 異常層次結構。
  • Spring ORM:Spring 框架插入了若干個 ORM 框架,從而提供了 ORM 的對象關係工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。全部這些都聽從 Spring 的通用事務和 DAO 異常層次結構。
  • Spring Web 模塊:Web 上下文模塊創建在應用程序上下文模塊之上,爲基於 Web 的應用程序提供了上下文。因此,Spring 框架支持與 Jakarta Struts 的集成。Web 模塊還簡化了處理多部分請求以及將請求參數綁定到域對象的工做。
  • Spring MVC 框架:MVC 框架是一個全功能的構建 Web 應用程序的 MVC 實現。經過策略接口,MVC 框架變成爲高度可配置的,MVC 容納了大量視圖技術,其中包括 JSP、Velocity、Tiles、iText 和 POI。

1.4拓展

Spring Boot與Spring Cloud

  • Spring Boot 是 Spring 的一套快速配置腳手架,能夠基於Spring Boot 快速開發單個微服務;
  • Spring Cloud是基於Spring Boot實現的;
  • Spring Boot專一於快速、方便集成的單個微服務個體,Spring Cloud關注全局的服務治理框架;
  • Spring Boot使用了約束優於配置的理念,不少集成方案已經幫你選擇好了,能不配置就不配置 , Spring Cloud很大的一部分是基於Spring Boot來實現,Spring Boot能夠離開Spring Cloud獨立使用開發項目,可是Spring Cloud離不開Spring Boot,屬於依賴的關係。
  • SpringBoot在SpringClound中起到了承上啓下的做用,若是你要學習SpringCloud必需要學習SpringBoot。

圖片

2.IoC基礎

新建一個空白的maven項目

分析實現(代碼)

咱們先用咱們原來的方式寫一段代碼 .

一、先寫一個UserDao接口

public interface UserDao {
    public void getUser();
}

二、再去寫Dao的實現類

public class UserDaoImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("獲取用戶數據");
    }
}

三、而後去寫UserService的接口

public interface UserService {
    public void getUser();
}

四、最後寫Service的實現類

public class UserServiceImpl implements UserService {
    private UserDao userDao = new UserDaoImpl();

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

五、測試一下

@Test
public void test(){
    UserService service = new UserServiceImpl();
    service.getUser();
}

這是咱們原來的方式 , 開始你們也都是這麼去寫的對吧 . 那咱們如今修改一下 .

把Userdao的實現類增長一個 .

public class UserDaoMySqlImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("MySql獲取用戶數據");
    }
}

緊接着咱們要去使用MySql的話 , 咱們就須要去service實現類裏面修改對應的實現

public class UserServiceImpl implements UserService {
    private UserDao userDao = new UserDaoMySqlImpl();

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

在假設, 咱們再增長一個Userdao的實現類 .

public class UserDaoOracleImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("Oracle獲取用戶數據");
    }
}

那麼咱們要使用Oracle , 又須要去service實現類裏面修改對應的實現 . 假設咱們的這種需求很是大 , 這種方式就根本不適用了, 甚至反人類對吧 , 每次變更 , 都須要修改大量代碼 . 這種設計的耦合性過高了, 牽一髮而動全身 .

那咱們如何去解決呢 ?

咱們能夠在須要用到他的地方 , 不去實現它 , 而是留出一個接口 , 利用set , 咱們去代碼裏修改下 .

public class UserServiceImpl implements UserService {
    private UserDao userDao;
// 利用set實現
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

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

如今去咱們的測試類裏 , 進行測試 ;

@Test
public void test(){
    UserServiceImpl service = new UserServiceImpl();
    service.setUserDao( new UserDaoMySqlImpl() );
    service.getUser();
    //那咱們如今又想用Oracle去實現呢
    service.setUserDao( new UserDaoOracleImpl() );
    service.getUser();
}
  • 以前是主動建立對象,控制權在程序員手上。
  • 使用set以後,是被動接受對象。

你們發現了區別沒有 ? 可能不少人說沒啥區別 . 可是同窗們 , 他們已經發生了根本性的變化 , 不少地方都不同了 . 仔細去思考一下 , 之前全部東西都是由程序去進行控制建立 , 而如今是由咱們自行控制建立對象 , 把主動權交給了調用者 . 程序不用去管怎麼建立,怎麼實現了 . 它只負責提供一個接口 .

這種思想 , 從本質上解決了問題 , 咱們程序員再也不去管理對象的建立了 , 更多的去關注業務的實現 . 耦合性大大下降 . 這也就是IOC的原型 !

IOC本質

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

圖片

IoC是Spring框架的核心內容,使用多種方式完美的實現了IoC,可使用XML配置,也可使用註解,新版本的Spring也能夠零配置實現IoC。

Spring容器在初始化時先讀取配置文件,根據配置文件或元數據建立與組織對象存入容器中,程序使用時再從Ioc容器中取出須要的對象。

圖片

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

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

3. Hello Spring

Hello代碼

pojo中

package com.th.pojo;

public class Hello {
    private String name;
    
    public String getName() {
        return name;
    }

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

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

resource種

<?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 = 變量名-->
    <!--class = new的對象-->
    <!--property 至關於給對象中的屬性設值-->
    
    <bean id="hello" class="com.th.pojo.Hello">
        <property name="name" value="Spring"/>
    </bean>
</beans>

test

import com.th.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Mytest {

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

思考

  • Hello 對象是誰建立的 ? 【hello 對象是由Spring建立的
  • Hello 對象的屬性是怎麼設置的 ? hello 對象的屬性是由Spring容器設置的

這個過程就叫控制反轉 :

  • 控制 : 誰來控制對象的建立 , 傳統應用程序的對象是由程序自己控制建立的 , 使用Spring後 , 對象是由Spring來建立的
  • 反轉 : 程序自己不建立對象 , 而變成被動的接收對象 .

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

IOC是一種編程思想,由主動的編程變成被動的接收

能夠經過newClassPathXmlApplicationContext去瀏覽一下底層源碼 .

修改案例一

咱們在案例一中, 新增一個Spring配置文件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
       http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean id="MysqlImpl" class="com.th.dao.impl.UserDaoMySqlImpl"/>
   <bean id="OracleImpl" class="com.th.dao.impl.UserDaoOracleImpl"/>

   <bean id="ServiceImpl" class="com.th.service.impl.UserServiceImpl">
       <!--注意: 這裏的name並非屬性 , 而是UserServiceImpl中的一個dao的接口對象(例如 private UserDao userDao;)-->
       <!--引用另一個bean , 不是用value 而是用 ref-->
       <property name="userDao" ref="OracleImpl"/><!--具體使用哪一個接口這裏能夠直接配置-->
   </bean>

</beans>

測試!

@Test
public void test2(){
   ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean("ServiceImpl");//這裏至關於將原來的Service層也IOC了,不須要再在代碼中寫出調用哪一個接口,只須要在配置文件中指明調用的接口便可。
   serviceImpl.getUser();
    //原來的步驟
    //UserService userService = new UserServiceImpl();
    //userService.setUserDao(new UserDaoMysqlImpl());//原先須要在代碼中調用特定的方法
	//userService.getUser();
}

OK , 到了如今 , 咱們完全不用再程序中去改動了 , 要實現不一樣的操做 , 只須要在xml配置文件中進行修改 , 所謂的IoC,一句話搞定 : 對象由Spring 來建立 , 管理 , 裝配 !

4. IOC建立對象的方式

4.1 使用無參構造建立對象,默認。

一、User.java

public class User {

   private String name;

   public User() {
       System.out.println("user無參構造方法");
  }

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

   public void show(){
       System.out.println("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"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean id="user" class="com.th.pojo.User">
       <property name="name" value="他化"/>
   </bean>

</beans>

三、測試類

<?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="user" class="com.th.pojo.User">
       <property name="name" value="他化"/>
   </bean>

</beans>

4.2使用有參構造

一、UserT . java

public class UserT {

   private String name;

   public UserT(String name) {
       this.name = name;
  }

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

   public void show(){
       System.out.println("name="+ name );
  }

}

二、beans.xml 有三種方式編寫

<!-- 第一種根據index參數下標設置 -->
<bean id="userT" class="com.th.pojo.UserT">
   <!-- index指構造方法 , 下標從0開始 -->
   <constructor-arg index="0" value="thshen2"/>
</bean>
<!-- 第二種根據參數名字設置 -->
<bean id="userT" class="com.th.pojo.UserT">
   <!-- name指參數名 -->
   <constructor-arg name="name" value="thshen2"/>
</bean>
<!-- 第三種根據參數類型設置(不推薦使用) -->
<bean id="userT" class="com.th.pojo.UserT">
   <constructor-arg type="java.lang.String" value="thshen2"/>
</bean>

三、測試

@Test
public void testT(){
   ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   UserT user = (UserT) context.getBean("userT");
   user.show();
}

結論:在配置文件加載的時候。其中管理的對象都已經初始化了!

5. Spring配置

5.1別名

alias 設置別名 , 爲bean設置別名 , 能夠設置多個別名

<!--設置別名:在獲取Bean的時候可使用別名獲取-->
<alias name="userT" alias="userNew"/>

5.2Bean的配置

<!--bean就是java對象,由Spring建立和管理-->

<!--
   id 是bean的標識符,要惟一,若是沒有配置id,name就是默認標識符
   若是配置id,又配置了name,那麼name是別名
   name能夠設置多個別名,能夠用逗號,分號,空格隔開
   若是不配置id和name,能夠根據applicationContext.getBean(.class)獲取對象;

class是bean的全限定名=包名+類名
-->
<bean id="hello" name="hello2 h2,h3;h4" class="com.th.pojo.Hello">
   <property name="name" value="Spring"/>
</bean>

import

通常用於團隊開發,它能夠將多個配置文件,導入合併爲一個

<import resource="beans.xml"/>

6. DI依賴注入

6.1構造器注入

參考上面,已經說過

6.2 set方式注入(重點)

  • 依賴:bean對象的建立依賴於容器
  • 注入:bean對象中的全部屬性,由容器來注入

【環境搭建】

  1. 複雜類型
  2. 真實測試對象

要求被注入的屬性 , 必須有set方法 , set方法的方法名由set + 屬性首字母大寫 , 若是屬性是boolean類型 , 沒有set方法 , 是 is .

  • Address.java

public class Address {

     private String address;
 
     public String getAddress() {
         return address;
    }
 
     public void setAddress(String address) {
         this.address = address;
    }
 }
  • Student.java

package com.th.pojo;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
 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;
 
     public void setName(String name) {
         this.name = name;
    }
 
     public void setAddress(Address address) {
         this.address = address;
    }
 
     public void setBooks(String[] books) {
         this.books = books;
    }
 
     public void setHobbys(List<String> hobbys) {
         this.hobbys = hobbys;
    }
 
     public void setCard(Map<String, String> card) {
         this.card = card;
    }
 
     public void setGames(Set<String> games) {
         this.games = games;
    }
 
     public void setWife(String wife) {
         this.wife = wife;
    }
 
     public void setInfo(Properties info) {
         this.info = info;
    }
 
     public void show(){
         System.out.println("name="+ name
                 + ",address="+ address.getAddress()
                 + ",books="
        );
         for (String book:books){
             System.out.print("<<"+book+">>\t");
        }
         System.out.println("\n愛好:"+hobbys);
 
         System.out.println("card:"+card);
 
         System.out.println("games:"+games);
 
         System.out.println("wife:"+wife);
 
         System.out.println("info:"+info);
 
    }
 }

一、常量注入

<bean id="student" class="com.th.pojo.Student">
     <property name="name" value="小明"/>
 </bean>

測試:

@Test
 public void test01(){
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
 
     Student student = (Student) context.getBean("student");
 
     System.out.println(student.getName());
 
 }

二、Bean注入

注意點:這裏的值是一個引用,ref

<bean id="addr" class="com.th.pojo.Address">
     <property name="address" value="重慶"/>
 </bean>
 
 <bean id="student" class="com.th.pojo.Student">
     <property name="name" value="小明"/>
     <property name="address" ref="addr"/>
 </bean>

三、數組注入

<bean id="student" class="com.th.pojo.Student">
     <property name="name" value="小明"/>
     <property name="address" ref="addr"/>
     <property name="books">
         <array>
             <value>西遊記</value>
             <value>紅樓夢</value>
             <value>水滸傳</value>
         </array>
     </property>
 </bean>

四、List注入

<property name="hobbys">
     <list>
         <value>聽歌</value>
         <value>看電影</value>
         <value>登山</value>
     </list>
 </property>

五、Map注入

<property name="card">
     <map>
         <entry key="中國郵政" value="456456456465456"/>
         <entry key="建設" value="1456682255511"/>
     </map>
 </property>

六、set注入

<property name="games">
     <set>
         <value>LOL</value>
         <value>BOB</value>
         <value>COC</value>
     </set>
 </property>

七、Null注入

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

八、Properties注入

<property name="info">
     <props>
         <prop key="學號">20190604</prop>
         <prop key="性別">男</prop>
         <prop key="姓名">小明</prop>
     </props>
 </property>

​ 測試結果:

img

6.3其餘方式注入

p命名空間注入

User.java :【注意:這裏沒有有參構造器!】
P命名空間注入 : 須要在頭文件中加入約束文件

導入約束 : xmlns:p="http://www.springframework.org/schema/p"
 
 <!--P(屬性: properties)命名空間 , 屬性依然要設置set方法-->
 <bean id="user" class="com.th.pojo.User" p:name="狂神老師" p:age="18"/>

C命名空間注入

c 命名空間注入 : 須要在頭文件中加入約束文件

導入約束 : xmlns:c="http://www.springframework.org/schema/c"
 <!--C(構造: Constructor)命名空間 , 屬性依然要設置set方法-->
 <bean id="user" class="com.th.pojo.User" c:name="天魔" c:age="18"/>

發現問題:爆紅了,剛纔咱們沒有寫有參構造!

解決:把有參構造器加上,這裏也能知道,c 就是所謂的構造器注入

測試代碼:

@Test
 public void test02(){
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
     User user = (User) context.getBean("user");
     System.out.println(user);
 }

6.4 Bean的做用域

​ 在Spring中,那些組成應用程序的主體及由Spring IoC容器所管理的對象,被稱之爲bean。簡單地講,bean就是由IoC容器初始化、裝配及管理的對象 .

img

​ 幾種做用域中,request、session做用域僅在基於web的應用中使用(沒必要關心你所採用的是什麼web應用框架),只能用在基於web的Spring ApplicationContext環境。

Singleton

當一個bean的做用域爲Singleton,那麼Spring IoC容器中只會存在一個共享的bean實例,而且全部對bean的請求,只要id與該bean定義相匹配,則只會返回bean的同一實例。Singleton是單例類型,就是在建立起容器時就同時自動建立了一個bean的對象,無論你是否使用,他都存在了,每次獲取到的對象都是同一個對象。注意,Singleton做用域是Spring中的缺省做用域。要在XML中將bean定義成singleton,能夠這樣配置:

<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">

單例模式也就是隻new一次對象,以後getBean的都直接獲取第一次new的對象

測試:

@Test
 public void test03(){
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
     User user = (User) context.getBean("user");
     User user2 = (User) context.getBean("user2");//第二次getBean
     System.out.println(user==user2);
 }

Prototype

當一個bean的做用域爲Prototype,表示一個bean定義對應多個對象實例。Prototype做用域的bean會致使在每次對該bean請求(將其注入到另外一個bean中,或者以程序的方式調用容器的getBean()方法)時都會建立一個新的bean實例。Prototype是原型類型,它在咱們建立容器的時候並無實例化,而是當咱們獲取bean的時候纔會去建立一個對象,並且咱們每次獲取到的對象都不是同一個對象。根據經驗,對有狀態的bean應該使用prototype做用域,而對無狀態的bean則應該使用singleton做用域。在XML中將bean定義成prototype,能夠這樣配置:

<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>  
  或者
 <bean id="account" class="com.foo.DefaultAccount" singleton="false"/>
  • 原型模式也就是在以後的getBean時從新new一個對象

其他的request、session、application這些只能在web開放中使用!

7. Bean的自動裝配

7.1自動裝配說明。

  • 自動裝配是使用spring知足bean依賴的一種方法
  • spring會在應用上下文中爲某個bean尋找其依賴的bean。

在Spring中有三種裝配的方式

  1. 在xml中顯示配置

  2. 在java中顯示配置

  3. 隱式的自動裝配bean 【重要】

這裏咱們主要講第三種:自動化的裝配bean。

Spring的自動裝配須要從兩個角度來實現,或者說是兩個操做:

  1. 組件掃描(component scanning):spring會自動發現應用上下文中所建立的bean;
  2. 自動裝配(autowiring):spring自動知足bean之間的依賴,也就是咱們說的IoC/DI;

組件掃描和自動裝配組合發揮巨大威力,使得顯示的配置下降到最少。

推薦不使用自動裝配和xml配置 , 而使用註解 .

7.2測試壞境搭建

一、新建一個項目

二、新建兩個實體類,Cat Dog 都有一個叫的方法

public class Cat {
   public void shout() {
       System.out.println("miao~");
  }
}
public class Dog {
   public void shout() {
       System.out.println("wang~");
  }
}

三、新建一個用戶類 User

public class User {
   private Cat cat;
   private Dog dog;
   private String str;
}

四、編寫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
       http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean id="dog" class="com.th.pojo.Dog"/>
   <bean id="cat" class="com.th.pojo.Cat"/>

   <bean id="user" class="com.th.pojo.User">
       <property name="cat" ref="cat"/>
       <property name="dog" ref="dog"/>
       <property name="str" value="他化"/>
   </bean>
</beans>

五、測試

public class MyTest {
   @Test
   public void testMethodAutowire() {
       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       User user = (User) context.getBean("user");
       user.getCat().shout();
       user.getDog().shout();
  }
}

結果正常輸出,環境OK

7.3 byName

autowire byName (按名稱自動裝配)

因爲在手動配置xml過程當中,經常發生字母缺漏和大小寫等錯誤,而沒法對其進行檢查,使得開發效率下降。

採用自動裝配將避免這些錯誤,而且使配置簡單化。

測試:

一、修改bean配置,增長一個屬性 autowire="byName"

<bean id="user" class="com.th.pojo.User" autowire="byName">
   <property name="str" value="他化"/>
</bean>

二、再次測試,結果依舊成功輸出!

三、咱們將 cat 的bean id修改成 catXXX

四、再次測試, 執行時報空指針java.lang.NullPointerException。由於按byName規則找不對應set方法,真正的setCat就沒執行,對象就沒有初始化,因此調用時就會報空指針錯誤。

小結:

當一個bean節點帶有 autowire byName的屬性時。

  1. 將查找其類中全部的set方法名,例如setCat,得到將set去掉而且首字母小寫的字符串,即cat。
  2. 去spring容器中尋找是否有此字符串名稱id的對象。
  3. 若是有,就取出注入;若是沒有,就報空指針異常。

7.4 byType

autowire byType (按類型自動裝配)

使用autowire byType首先須要保證:同一類型的對象,在spring容器中惟一。若是不惟一,會報不惟一的異常。

NoUniqueBeanDefinitionException

測試:

一、將user的bean配置修改一下 : autowire="byType"

二、測試,正常輸出

三、在註冊一個cat 的bean對象!

<bean id="dog" class="com.th.pojo.Dog"/>
<bean id="cat" class="com.th.pojo.Cat"/>
<bean id="cat2" class="com.th.pojo.Cat"/>

<bean id="user" class="com.th.pojo.User" autowire="byType">
   <property name="str" value="他化"/>
</bean>

四、測試,報錯:NoUniqueBeanDefinitionException

五、刪掉cat2,將cat的bean名稱改掉!測試!由於是按類型裝配,因此並不會報異常,也不影響最後的結果。甚至將id屬性去掉,也不影響結果。

這就是按照類型自動裝配!

7.5 使用註解實現自動配置

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

jdk1.5開始支持註解,spring2.5開始全面支持註解。

準備工做:利用註解的方式注入屬性。

一、在spring配置文件中引入context文件頭

xmlns:context="http://www.springframework.org/schema/context"

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd

二、開啓屬性註解支持!

<context:annotation-config/>

@Autowired

  • @Autowired是按類型自動轉配的,不支持id匹配。
  • 須要導入 spring-aop的包!

測試:

一、將User類中的set方法去掉,使用@Autowired註解

public class User {
   @Autowired
   private Cat cat;
   @Autowired
   private Dog dog;
   private String str;

   public Cat getCat() {
       return cat;
  }
   public Dog getDog() {
       return dog;
  }
   public String getStr() {
       return str;
  }
}

二、此時配置文件內容

<context:annotation-config/>

<bean id="dog" class="com.th.pojo.Dog"/>
<bean id="cat" class="com.th.pojo.Cat"/>
<bean id="user" class="com.th.pojo.User"/>

三、測試,成功輸出結果!

【小狂神科普時間】

@Autowired(required=false) 說明:false,對象能夠爲null;true,對象必須存對象,不能爲null。

//若是容許對象爲null,設置required = false,默認爲true
@Autowired(required = false)
private Cat cat;

@Qualifier

  • @Autowired是根據類型自動裝配的,加上@Qualifier則能夠根據byName的方式自動裝配
  • @Qualifier不能單獨使用。

測試實驗步驟:

一、配置文件修改內容,保證類型存在對象。且名字不爲類的默認名字!

<bean id="dog1" class="com.th.pojo.Dog"/>
<bean id="dog2" class="com.th.pojo.Dog"/>
<bean id="cat1" class="com.th.pojo.Cat"/>
<bean id="cat2" class="com.th.pojo.Cat"/>

二、沒有加Qualifier測試,直接報錯

三、在屬性上添加Qualifier註解

@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;

測試,成功輸出!

@Resource

  • @Resource若有指定的name屬性,先按該屬性進行byName方式查找裝配;
  • 其次再進行默認的byName方式進行裝配;
  • 若是以上都不成功,則按byType的方式自動裝配。
  • 都不成功,則報異常。

實體類:

public class User {
   //若是容許對象爲null,設置required = false,默認爲true
   @Resource(name = "cat2")
   private Cat cat;
   @Resource
   private Dog dog;
   private String str;
}

beans.xml

<bean id="dog" class="com.th.pojo.Dog"/>
<bean id="cat1" class="com.th.pojo.Cat"/>
<bean id="cat2" class="com.th.pojo.Cat"/>

<bean id="user" class="com.th.pojo.User"/>

測試:結果OK

配置文件2:beans.xml , 刪掉cat2

<bean id="dog" class="com.th.pojo.Dog"/>
<bean id="cat1" class="com.th.pojo.Cat"/>

實體類上只保留註解

@Resource
private Cat cat;
@Resource
private Dog dog;

結果:OK

結論:先進行byType查找,失敗;再進行byName查找,成功。

小節

@Autowired與@Resource異同:

一、@Autowired與@Resource均可以用來裝配bean。均可以寫在字段上,或寫在setter方法上。

二、@Autowired默認按類型裝配(屬於spring規範),默認狀況下必需要求依賴對象必須存在,若是要容許null 值,能夠設置它的required屬性爲false,如:@Autowired(required=false) ,若是咱們想使用名稱裝配能夠結合@Qualifier註解進行使用

三、@Resource(屬於J2EE復返),默認按照名稱進行裝配,名稱能夠經過name屬性進行指定。若是沒有指定name屬性,當註解寫在字段上時,默認取字段名進行按照名稱查找,若是註解寫在setter方法上默認取屬性名進行裝配。當找不到與名稱匹配的bean時才按照類型進行裝配。可是須要注意的是,若是name屬性一旦指定,就只會按照名稱進行裝配。

它們的做用相同都是用註解方式注入對象,但執行順序不一樣。@Autowired先byType,@Resource先byName。

8. 使用註解開發

8.1說明

在spring4以後,必需要保證aop的包導入

img

使t用註解須要導入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
       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>

8.2 Bean的實現

咱們以前都是使用 bean 的標籤進行bean注入,可是實際開發中,咱們通常都會使用註解!

一、配置掃描哪些包下的註解

<!--指定註解掃描包-->
<context:component-scan base-package="com.th.pojo"/>

二、在指定包下編寫類,增長註解

@Component("user")
// 至關於配置文件中 <bean id="user" class="當前註解的類"/>
public class User {
   public String name = "秦疆";
}

三、測試

@Test
public void test(){
   ApplicationContext applicationContext =
       new ClassPathXmlApplicationContext("beans.xml");
   User user = (User) applicationContext.getBean("user");
   System.out.println(user.name);
}

8.三、屬性注入

使用註解注入屬性

一、能夠不用提供set方法,直接在直接名上添加@value("值")

@Component("user")
// 至關於配置文件中 <bean id="user" class="當前註解的類"/>
public class User {
   @Value("秦疆")
   // 至關於配置文件中 <property name="name" value="秦疆"/>
   public String name;
}

二、若是提供了set方法,在set方法上添加@value("值");

@Component("user")
public class User {

   public String name;

   @Value("秦疆")
   public void setName(String name) {
       this.name = name;
  }
}

8.四、衍生註解

咱們這些註解,就是替代了在配置文件當中配置步驟而已!更加的方便快捷!

@Component三個衍生註解

爲了更好的進行分層,Spring可使用其它三個註解,功能同樣,目前使用哪個功能都同樣。

  • @Controller:web層
  • @Service:service層
  • @Repository:dao層

寫上這些註解,就至關於將這個類交給Spring管理裝配了!

8.五、自動裝配註解

在Bean的自動裝配已經講過了,能夠回顧!

8.六、做用域

@scope

  • singleton:默認的,Spring會採用單例模式建立這個對象。關閉工廠 ,全部的對象都會銷燬。
  • prototype:多例模式。關閉工廠 ,全部的對象不會銷燬。內部的垃圾回收機制會回收
@Controller("user")
@Scope("prototype")
public class User {
   @Value("秦疆")
   public String name;
}

8.七、小結

XML與註解比較

  • XML能夠適用任何場景 ,結構清晰,維護方便
  • 註解不是本身提供的類使用不了,開發簡單方便

xml與註解整合開發 :推薦最佳實踐

  • xml管理Bean
  • 註解完成屬性注入
  • 使用過程當中, 能夠不用掃描,掃描是爲了類上的註解
<context:annotation-config/>

做用:

  • 進行註解驅動註冊,從而使註解生效
  • 用於激活那些已經在spring容器裏註冊過的bean上面的註解,也就是顯示的向Spring註冊
  • 若是不掃描包,就須要手動配置bean
  • 若是不加註解驅動,則注入的值爲null!

9. 使用java方式配置spring

徹底不使用xml配置

JavaConfig 原來是 Spring 的一個子項目,它經過 Java 類的方式提供 Bean 的定義信息,在 Spring4 的版本, JavaConfig 已正式成爲 Spring4 的核心功能 。

測試:

一、編寫一個實體類,Dog

@Component  //將這個類標註爲Spring的一個組件,放到容器中!
public class Dog {
   public String name = "dog";
}

二、新建一個config配置包,編寫一個MyConfig配置類

@Configuration  //表明這是一個配置類
public class MyConfig {

   @Bean //經過方法註冊一個bean,這裏的返回值就Bean的類型,方法名就是bean的id!
   public Dog dog(){
       return new Dog();
  }

}

三、測試

@Test
public void test2(){
   ApplicationContext applicationContext =
           new AnnotationConfigApplicationContext(MyConfig.class);
   Dog dog = (Dog) applicationContext.getBean("dog");
   System.out.println(dog.name);
}

四、成功輸出結果!

導入其餘配置如何作呢?

一、咱們再編寫一個配置類!

@Configuration  //表明這是一個配置類
public class MyConfig2 {
}

二、在以前的配置類中咱們來選擇導入這個配置類

@Configuration
@Import(MyConfig2.class)  //導入合併其餘配置類,相似於配置文件中的 inculde 標籤
public class MyConfig {

   @Bean
   public Dog dog(){
       return new Dog();
  }

}

關於這種Java類的配置方式,咱們在以後的SpringBoot 和 SpringCloud中還會大量看到,咱們須要知道這些註解的做用便可!

10. 動態代理

爲何要學習代理模式,由於AOP的底層機制就是動態代理!【SpringAOP和SpringMVC】

代理模式:

  • 靜態代理
  • 動態代理

學習aop以前 , 咱們要先了解一下代理模式!

img

10.一、靜態代理

靜態代理角色分析

  • 抽象角色 : 通常使用接口或者抽象類來實現
  • 真實角色 : 被代理的角色
  • 代理角色 : 代理真實角色 ; 代理真實角色後 , 通常會作一些附屬的操做 .
  • 客戶 : 使用代理角色來進行一些操做 .

代碼實現

Rent . java 即抽象角色

//抽象角色:租房
public interface Rent {
   public void rent();
}

Host . java 即真實角色

//真實角色: 房東,房東要出租房子
public class Host implements Rent{
   public void rent() {
       System.out.println("房屋出租");
  }
}

Proxy . java 即代理角色

//代理角色:中介
public class Proxy implements Rent {

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

   //租房
   public void rent(){
       seeHouse();
       host.rent();
       fare();
  }
   //看房
   public void seeHouse(){
       System.out.println("帶房客看房");
  }
   //收中介費
   public void fare(){
       System.out.println("收中介費");
  }
}

Client . java 即客戶

//客戶類,通常客戶都會去找代理!
public class Client {
   public static void main(String[] args) {
       //房東要租房
       Host host = new Host();
       //中介幫助房東
       Proxy proxy = new Proxy(host);

       //你去找中介!
       proxy.rent();
  }
}

分析:在這個過程當中,你直接接觸的就是中介,就如同現實生活中的樣子,你看不到房東,可是你依舊租到了房東的房子經過代理,這就是所謂的代理模式,程序源自於生活,因此學編程的人,通常可以更加抽象的看待生活中發生的事情。

靜態代理的好處:

  • 可使得咱們的真實角色更加純粹 . 再也不去關注一些公共的事情 .
  • 公共的業務由代理來完成 . 實現了業務的分工 ,
  • 公共業務發生擴展時變得更加集中和方便 .

缺點 :

  • 類多了 , 多了代理類 , 工做量變大了 . 開發效率下降 .

咱們想要靜態代理的好處,又不想要靜態代理的缺點,因此 , 就有了動態代理 !

10.2 加深理解

同窗們練習完畢後,咱們再來舉一個例子,鞏固你們的學習!

練習步驟:

一、建立一個抽象角色,好比咋們平時作的用戶業務,抽象起來就是增刪改查!

//抽象角色:增刪改查業務
public interface UserService {
   void add();
   void delete();
   void update();
   void query();
}

二、咱們須要一個真實對象來完成這些增刪改查操做

//真實對象,完成增刪改查操做的人
public class UserServiceImpl implements UserService {

   public void add() {
       System.out.println("增長了一個用戶");
  }

   public void delete() {
       System.out.println("刪除了一個用戶");
  }

   public void update() {
       System.out.println("更新了一個用戶");
  }

   public void query() {
       System.out.println("查詢了一個用戶");
  }
}

三、需求來了,如今咱們須要增長一個日誌功能,怎麼實現!

  • 思路1 :在實現類上增長代碼 【麻煩!】
  • 思路2:使用代理來作,可以不改變原來的業務狀況下,實現此功能就是最好的了!

四、設置一個代理類來處理日誌!代理角色

//代理角色,在這裏面增長日誌的實現
public class UserServiceProxy implements UserService {
   private UserServiceImpl userService;

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

   public void add() {
       log("add");
       userService.add();
  }

   public void delete() {
       log("delete");
       userService.delete();
  }

   public void update() {
       log("update");
       userService.update();
  }

   public void query() {
       log("query");
       userService.query();
  }

   public void log(String msg){
       System.out.println("執行了"+msg+"方法");
  }

}

五、測試訪問類:

public class Client {
   public static void main(String[] args) {
       //真實業務
       UserServiceImpl userService = new UserServiceImpl();
       //代理類
       UserServiceProxy proxy = new UserServiceProxy();
       //使用代理類實現日誌功能!
       proxy.setUserService(userService);

       proxy.add();
  }
}

OK,到了如今代理模式你們應該都沒有什麼問題了,重點你們須要理解其中的思想;

咱們在不改變原來的代碼的狀況下,實現了對原有功能的加強,這是AOP中最核心的思想

聊聊AOP:縱向開發,橫向開發

img

10.三、動態代理

  • 動態代理的角色和靜態代理的同樣 .
  • 動態代理的代理類是動態生成的 . 靜態代理的代理類是咱們提早寫好的
  • 動態代理分爲兩類 : 一類是基於接口動態代理 , 一類是基於類的動態代理
    • 基於接口的動態代理----JDK動態代理
    • 基於類的動態代理--cglib
    • 如今用的比較多的是 javasist 來生成動態代理 . 百度一下javasist
    • 咱們這裏使用JDK的原生代碼來實現,其他的道理都是同樣的!、

JDK的動態代理須要瞭解兩個類

核心 : InvocationHandler 和 Proxy , 打開JDK幫助文檔看看

【InvocationHandler:調用處理程序】

img

Object invoke(Object proxy, 方法 method, Object[] args);
//參數
//proxy - 調用該方法的代理實例
//method -所述方法對應於調用代理實例上的接口方法的實例。方法對象的聲明類將是該方法聲明的接口,它能夠是代理類繼承該方法的代理接口的超級接口。
//args -包含的方法調用傳遞代理實例的參數值的對象的陣列,或null若是接口方法沒有參數。原始類型的參數包含在適當的原始包裝器類的實例中,例如java.lang.Integer或java.lang.Boolean 。

【Proxy : 代理】

img

img

img

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

代碼實現

抽象角色和真實角色和以前的同樣!

Rent . java 即抽象角色

//抽象角色:租房
public interface Rent {
   public void rent();
}

Host . java 即真實角色j

//真實角色: 房東,房東要出租房子
public class Host implements Rent{
   public void rent() {
       System.out.println("房屋出租");
  }
}

ProxyInvocationHandler. java 即代理角色

public class ProxyInvocationHandler implements InvocationHandler {
   private Rent rent;

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

   //生成代理類,重點是第二個參數,獲取要代理的抽象角色!以前都是一個角色,如今能夠代理一類角色
   public Object getProxy(){
       return Proxy.newProxyInstance(this.getClass().getClassLoader(),
               rent.getClass().getInterfaces(),this);
  }

   // proxy : 代理類 method : 代理類的調用處理程序的方法對象.
   // 處理代理實例上的方法調用並返回結果
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       seeHouse();
       //核心:本質利用反射實現!
       Object result = method.invoke(rent, args);
       fare();
       return result;
  }

   //看房
   public void seeHouse(){
       System.out.println("帶房客看房");
  }
   //收中介費
   public void fare(){
       System.out.println("收中介費");
  }

}

Client . java

//租客
public class Client {

   public static void main(String[] args) {
       //真實角色
       Host host = new Host();
       //代理實例的調用處理程序
       ProxyInvocationHandler pih = new ProxyInvocationHandler();
       pih.setRent(host); //將真實角色放置進去!
       Rent proxy = (Rent)pih.getProxy(); //動態生成對應的代理類!
       proxy.rent();
  }

}

核心:一個動態代理 , 通常代理某一類業務 , 一個動態代理能夠代理多個類,代理的是接口!、

10.4深化理解

咱們來使用動態代理實現代理咱們後面寫的UserService!

咱們也能夠編寫一個通用的動態代理實現的類!全部的代理對象設置爲Object便可!

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

   // proxy : 代理類
   // method : 代理類的調用處理程序的方法對象.
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       log(method.getName());
       Object result = method.invoke(target, args);
       return result;
  }

   public void log(String methodName){
       System.out.println("執行了"+methodName+"方法");
  }

}

測試!

public class Test {
   public static void main(String[] args) {
       //真實對象
       UserServiceImpl userService = new UserServiceImpl();
       //代理對象的調用處理程序
       ProxyInvocationHandler pih = new ProxyInvocationHandler();
       pih.setTarget(userService); //設置要代理的對象
       UserService proxy = (UserService)pih.getProxy(); //動態生成代理類!
       proxy.delete();
  }
}

測試,增刪改查,查看結果!

動態代理的好處

靜態代理有的它都有,靜態代理沒有的,它也有!

  • 可使得咱們的真實角色更加純粹 . 再也不去關注一些公共的事情 .
  • 公共的業務由代理來完成 . 實現了業務的分工 ,
  • 公共業務發生擴展時變得更加集中和方便 .
  • 一個動態代理 , 通常代理某一類業務
  • 一個動態代理能夠代理多個類,代理的是接口!

11.AOP

那咱們接下來就來聊聊AOP吧!

11.一、什麼是AOP

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

img

11.二、Aop在Spring中的做用

提供聲明式事務;容許用戶自定義切面

如下名詞須要瞭解下:

  • 橫切關注點:跨越應用程序多個模塊的方法或功能。便是,與咱們業務邏輯無關的,可是咱們須要關注的部分,就是橫切關注點。如日誌 , 安全 , 緩存 , 事務等等 ....
  • 切面(ASPECT):橫切關注點 被模塊化 的特殊對象。即,它是一個類。
  • 通知(Advice):切面必需要完成的工做。即,它是類中的一個方法。
  • 目標(Target):被通知對象。
  • 代理(Proxy):向目標對象應用通知以後建立的對象。
  • 切入點(PointCut):切面通知 執行的 「地點」的定義。
  • 鏈接點(JointPoint):與切入點匹配的執行點。

img

SpringAOP中,經過Advice定義橫切邏輯,Spring中支持5種類型的Advice:

img

即 Aop 在 不改變原有代碼的狀況下 , 去增長新的功能 .

11.三、使用Spring實現Aop

【重點】使用AOP織入,須要導入一個依賴包!

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

第一種方式

1.經過 Spring API 實現

首先編寫咱們的業務接口和實現類

public interface UserService {

   public void add();

   public void delete();

   public void update();

   public void search();

}
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 search() {
       System.out.println("查詢用戶");
  }
}

而後去寫咱們的加強類 , 咱們編寫兩個 , 一個前置加強 一個後置加強

public class Log implements MethodBeforeAdvice {

   //method : 要執行的目標對象的方法
   //objects : 被調用的方法的參數
   //Object : 目標對象
   @Override
   public void before(Method method, Object[] objects, Object o) throws Throwable {
       System.out.println( o.getClass().getName() + "的" + method.getName() + "方法被執行了");
  }
}
public class AfterLog implements AfterReturningAdvice {
   //returnValue 返回值
   //method被調用的方法
   //args 被調用的方法的對象的參數
   //target 被調用的目標對象
   @Override
   public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
       System.out.println("執行了" + target.getClass().getName()
       +"的"+method.getName()+"方法,"
       +"返回值:"+returnValue);
  }
}

最後去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: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">

   <!--註冊bean-->
   <bean id="userService" class="com.th.service.UserServiceImpl"/>
   <bean id="log" class="com.th.log.Log"/>
   <bean id="afterLog" class="com.th.log.AfterLog"/>

   <!--aop的配置-->
   <aop:config>
       <!--切入點 expression:表達式匹配要執行的方法-->
       <aop:pointcut id="pointcut" expression="execution(* com.th.service.UserServiceImpl.*(..))"/>
       <!--執行環繞; advice-ref執行方法 . pointcut-ref切入點-->
       <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
       <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
   </aop:config>
</beans>

測試

public class MyTest {
   @Test
   public void test(){
       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       UserService userService = (UserService) context.getBean("userService");
       userService.search();
  }
}

Aop的重要性 : 很重要 . 必定要理解其中的思路 , 主要是思想的理解這一塊 .

Spring的Aop就是將公共的業務 (日誌 , 安全等) 和領域業務結合起來 , 當執行領域業務時 , 將會把公共業務加進來 . 實現公共業務的重複利用 . 領域業務更純粹 , 程序猿專一領域業務 , 其本質仍是動態代理 .

第二種方式

2.自定義類來實現Aop

目標業務類不變依舊是userServiceImpl

第一步 : 寫咱們本身的一個切入類

public class DiyPointcut {

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

去spring中配置

<!--第二種方式自定義實現-->
<!--註冊bean-->
<bean id="diy" class="com.th.config.DiyPointcut"/>

<!--aop的配置-->
<aop:config>
   <!--第二種方式:使用AOP的標籤實現-->
   <aop:aspect ref="diy">
       <aop:pointcut id="diyPonitcut" expression="execution(* com.th.service.UserServiceImpl.*(..))"/>
       <aop:before pointcut-ref="diyPonitcut" method="before"/>
       <aop:after pointcut-ref="diyPonitcut" method="after"/>
   </aop:aspect>
</aop:config>

測試:

public class MyTest {
   @Test
   public void test(){
       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       UserService userService = (UserService) context.getBean("userService");
       userService.add();
  }
}

第三種方式

3.使用註解實現

第一步:編寫一個註解實現的加強類

package com.th.config;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class AnnotationPointcut {
   @Before("execution(* com.th.service.UserServiceImpl.*(..))")
   public void before(){
       System.out.println("---------方法執行前---------");
  }

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

   @Around("execution(* com.th.service.UserServiceImpl.*(..))")
   public void around(ProceedingJoinPoint jp) throws Throwable {
       System.out.println("環繞前");
       System.out.println("簽名:"+jp.getSignature());
       //執行目標方法proceed
       Object proceed = jp.proceed();
       System.out.println("環繞後");
       System.out.println(proceed);
  }
}

第二步:在Spring配置文件中,註冊bean,並增長支持註解的配置

<!--第三種方式:註解實現-->
<bean id="annotationPointcut" class="com.th.config.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>

aop:aspectj-autoproxy:說明

經過aop命名空間的<aop:aspectj-autoproxy />聲明自動爲spring容器中那些配置@aspectJ切面的bean建立代理,織入切面。固然,spring 在內部依舊採用AnnotationAwareAspectJAutoProxyCreator進行自動代理的建立工做,但具體實現的細節已經被<aop:aspectj-autoproxy />隱藏起來了
<aop:aspectj-autoproxy />有一個proxy-target-class屬性,默認爲false,表示使用jdk動態代理織入加強,當配爲<aop:aspectj-autoproxy  poxy-target-class="true"/>時,表示使用CGLib動態代理技術織入加強。不過即便proxy-target-class設置爲false,若是目標類沒有聲明接口,則spring將自動使用CGLib動態代理。

到了這裏,AOP的思想和使用相信你們就沒問題了!

12. 整合mybatis

依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-study</artifactId>
        <groupId>com.hou</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring-10-mybatis</artifactId>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.4</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>


        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

</project>

12.1步驟

一、導入相關jar包

junit

<dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.12</version>
</dependency>

mybatis

<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis</artifactId>
   <version>3.5.2</version>
</dependency>

mysql-connector-javax

<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.47</version>
</dependency>

spring相關

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>5.1.10.RELEASE</version>
</dependency>
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-jdbc</artifactId>
   <version>5.1.10.RELEASE</version>
</dependency>

aspectJ AOP 織入器

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

mybatis-spring整合包 【重點】

<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis-spring</artifactId>
   <version>2.0.2</version>
</dependency>

配置Maven靜態資源過濾問題!

<build>
   <resources>
       <resource>
           <directory>src/main/java</directory>
           <includes>
               <include>**/*.properties</include>
               <include>**/*.xml</include>
           </includes>
           <filtering>true</filtering>
       </resource>
   </resources>
</build>

二、編寫配置文件

三、代碼實現

12.2 回憶MyBatis

編寫pojo實體類

package com.th.pojo;

public class User {
   private int id;  //id
   private String name;   //姓名
   private String pwd;   //密碼
}

實現mybatis的配置文件

<?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.th.pojo"/>
   </typeAliases>

   <environments default="development">
       <environment id="development">
           <transactionManager type="JDBC"/>
           <dataSource type="POOLED">
               <property name="driver" value="com.mysql.jdbc.Driver"/>
               <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
               <property name="username" value="root"/>
               <property name="password" value="root"/>
           </dataSource>
       </environment>
   </environments>

   <mappers>
       <package name="com.th.dao"/>
   </mappers>
</configuration>

UserDao接口編寫

public interface UserMapper {
   public List<User> selectUser();
}

接口對應的Mapper映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
       PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.th.dao.UserMapper">

   <select id="selectUser" resultType="User">
    select * from user
   </select>

</mapper>

測試類

@Test
public void selectUser() throws IOException {

   String resource = "mybatis-config.xml";
   InputStream inputStream = Resources.getResourceAsStream(resource);
   SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
   SqlSession sqlSession = sqlSessionFactory.openSession();

   UserMapper mapper = sqlSession.getMapper(UserMapper.class);

   List<User> userList = mapper.selectUser();
   for (User user: userList){
       System.out.println(user);
  }

   sqlSession.close();
}

12.三、MyBatis-Spring學習

引入Spring以前須要瞭解mybatis-spring包中的一些重要類;

文檔 :http://www.mybatis.org/spring/zh/index.html

什麼是 MyBatis-Spring?

MyBatis-Spring 會幫助你將 MyBatis 代碼無縫地整合到 Spring 中。

知識基礎

在開始使用 MyBatis-Spring 以前,你須要先熟悉 Spring 和 MyBatis 這兩個框架和有關它們的術語。這很重要

MyBatis-Spring 須要如下版本:

MyBatis-Spring MyBatis Spring 框架 Spring Batch Java
2.0 3.5+ 5.0+ 4.0+ Java 8+
1.3 3.4+ 3.2.2+ 2.1+ Java 6+

若是使用 Maven 做爲構建工具,僅須要在 pom.xml 中加入如下代碼便可:

<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis-spring</artifactId>
   <version>2.0.2</version>
</dependency>

要和 Spring 一塊兒使用 MyBatis,須要在 Spring 應用上下文中定義至少兩樣東西:一個 SqlSessionFactory 和至少一個數據映射器類。

在 MyBatis-Spring 中,可以使用SqlSessionFactoryBean來建立 SqlSessionFactory。要配置這個工廠 bean,只須要把下面代碼放在 Spring 的 XML 配置文件中:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 <property name="dataSource" ref="dataSource" />
</bean>

注意:SqlSessionFactory須要一個 DataSource(數據源)。這能夠是任意的 DataSource,只須要和配置其它 Spring 數據庫鏈接同樣配置它就能夠了。

在基礎的 MyBatis 用法中,是經過 SqlSessionFactoryBuilder 來建立 SqlSessionFactory 的。而在 MyBatis-Spring 中,則使用 SqlSessionFactoryBean 來建立。

在 MyBatis 中,你可使用 SqlSessionFactory 來建立 SqlSession。一旦你得到一個 session 以後,你可使用它來執行映射了的語句,提交或回滾鏈接,最後,當再也不須要它的時候,你能夠關閉 session。

SqlSessionFactory有一個惟一的必要屬性:用於 JDBC 的 DataSource。這能夠是任意的 DataSource 對象,它的配置方法和其它 Spring 數據庫鏈接是同樣的。

一個經常使用的屬性是 configLocation,它用來指定 MyBatis 的 XML 配置文件路徑。它在須要修改 MyBatis 的基礎配置很是有用。一般,基礎配置指的是 < settings> 或 < typeAliases>元素。

須要注意的是,這個配置文件並不須要是一個完整的 MyBatis 配置。確切地說,任何環境配置(),數據源()和 MyBatis 的事務管理器()都會被忽略。SqlSessionFactoryBean 會建立它自有的 MyBatis 環境配置(Environment),並按要求設置自定義環境的值。

SqlSessionTemplate 是 MyBatis-Spring 的核心。做爲 SqlSession 的一個實現,這意味着可使用它無縫代替你代碼中已經在使用的 SqlSession。

模板能夠參與到 Spring 的事務管理中,而且因爲其是線程安全的,能夠供多個映射器類使用,你應該老是用 SqlSessionTemplate 來替換 MyBatis 默認的 DefaultSqlSession 實現。在同一應用程序中的不一樣類之間混雜使用可能會引發數據一致性的問題。

可使用 SqlSessionFactory 做爲構造方法的參數來建立 SqlSessionTemplate 對象。

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

如今,這個 bean 就能夠直接注入到你的 DAO bean 中了。你須要在你的 bean 中添加一個 SqlSession 屬性,就像下面這樣:

public class UserDaoImpl implements UserDao {

 private SqlSession sqlSession;

 public void setSqlSession(SqlSession sqlSession) {
   this.sqlSession = sqlSession;
}

 public User getUser(String userId) {
   return sqlSession.getMapper...;
}

按下面這樣,注入 SqlSessionTemplate:

<bean id="userDao" class="org.mybatis.spring.sample.dao.UserDaoImpl">
 <property name="sqlSession" ref="sqlSession" />
</bean>

12.4整合實現一

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

    <!--data source-->
    <!--配置數據源:數據源有很是多,可使用第三方的,也可以使使用Spring的-->
    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

    <!--sqlsession-->
    <!--配置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/th/dao/*.xml"/>
    </bean>

    <!--註冊sqlSessionTemplate , 關聯sqlSessionFactory-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--利用構造器注入-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <bean id="userDao" class="com.th.dao.UserDaoImpl">
   		<property name="sqlSession" ref="sqlSession"/>
	</bean>

</beans>

一、引入Spring配置文件Spring-dao.xml(名字隨便起)最後導入到applicationContext.xml 測試中就能夠直接這個applicationContext.xml

二、配置數據源替換mybaits的數據源

三、配置SqlSessionFactory,關聯MyBatis

四、註冊sqlSessionTemplate,關聯sqlSessionFactory;

五、增長Dao接口的實現類;私有化sqlSessionTemplate

public class UserDaoImpl implements UserMapper {

   //sqlSession不用咱們本身建立了,Spring來管理
   private SqlSessionTemplate sqlSession;

   public void setSqlSession(SqlSessionTemplate sqlSession) {
       this.sqlSession = sqlSession;
  }

   public List<User> selectUser() {
       UserMapper mapper = sqlSession.getMapper(UserMapper.class);
       return mapper.selectUser();
  }
   
}

六、註冊bean實現

<bean id="userDao" class="com.th.dao.UserDaoImpl">
   <property name="sqlSession" ref="sqlSession"/>
</bean>

七、測試

先applicationContext.xml中導入一下

@Test
   public void test2(){
       ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
       UserMapper mapper = (UserMapper) context.getBean("userDao");
       List<User> user = mapper.selectUser();
       System.out.println(user);
  }

結果成功輸出!如今咱們的Mybatis配置文件的狀態!發現均可以被Spring整合!

<?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.th.pojo"/>
   </typeAliases>
</configuration>

12.5整合實現二

mybatis-spring1.2.3版以上的纔有這個 .

官方文檔截圖 :

dao繼承Support類 , 直接利用 getSqlSession() 得到 , 而後直接注入SqlSessionFactory . 比起方式1 , 不須要管理SqlSessionTemplate , 並且對事務的支持更加友好 . 可跟蹤源碼查看

img

測試:

一、將咱們上面寫的UserDaoImpl修改一下

public class UserDaoImpl extends SqlSessionDaoSupport implements UserMapper {
   public List<User> selectUser() {
       UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
       return mapper.selectUser();
  }
}

二、修改bean的配置

<bean id="userDao" class="com.th.dao.UserDaoImpl">
   <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

三、測試

@Test
public void test2(){
   ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
   UserMapper mapper = (UserMapper) context.getBean("userDao");
   List<User> user = mapper.selectUser();
   System.out.println(user);
}

總結 : 整合到spring之後能夠徹底不要mybatis的配置文件,除了這些方式能夠實現整合以外,咱們還可使用註解來實現,這個等咱們後面學習SpringBoot的時候還會測試整合!

13. Spring中的事務管理(完整代碼)

  • 要麼都成功,要麼都失敗
  • 十分重要,涉及到數據一致性
  • 確保完整性和一致性

事務的ACID原則:

  • 原子性
  • 一致性
  • 隔離性
    • 多個業務可能操做一個資源,防止數據損壞
  • 持久性
    • 事務一旦提交,不管系統發生什麼問題,結果都不會被影響。

Spring中的事務管理

  • 聲明式事務
  • 編程式事務

聲明式事務

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

    <!--data source-->
    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

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

    <!--聲明式事務-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg ref="datasource" />
    </bean>

    <!--結合aop實現事務置入-->
    <!--配置事務的類-->
    <tx:advice id="tx1" transaction-manager="transactionManager">
        <!--給哪些方法配置事務-->
        <!--配置事務的傳播特性-->
        <tx:attributes>
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="delete" propagation="REQUIRED"/>
            <tx:method name="update" propagation="REQUIRED"/>
            <tx:method name="*" propagation="REQUIRED"/>
            <tx:method name="query" read-only="true"/>
        </tx:attributes>
    </tx:advice>

    <!--配置事務切入-->
    <aop:config>
        <aop:pointcut id="txpointxut" expression="execution(* com.mapper.*.*(..))"/>
        <aop:advisor advice-ref="tx1" pointcut-ref="txpointxut"/>
    </aop:config>

</beans>

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="spring-dao.xml"/>

    <bean id="userMapper2" class="com.mapper.UserMapperIml2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
    </bean>

</beans>

UserMapper接口

package com.mapper;

import com.pojo.User;

import java.util.List;

public interface UserMapper {
    List<User> selectUser();
    int addUser(User user);
    int delete(int id);
}

UserMapper.xml

<?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.mapper.UserMapper">
    <select id="selectUser" resultType="user">
        select * from mybatis.user;
    </select>

    <insert id="addUser" parameterType="user">
        insert into mybatis.user (id, name, pwd) values
        (#{id}, #{name}, #{pwd})
    </insert>

    <delete id="delete" parameterType="int">
        delete from mybatis.user where id=#{id}
    </delete>
</mapper>

UserMapperIml2實現類

package com.mapper;

import com.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class UserMapperIml2 extends SqlSessionDaoSupport implements UserMapper {

    public List<User> selectUser() {
        User user = new User(6, "天魔", "333");
        SqlSession sqlSession = getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.addUser(user);
        mapper.delete(6);
        return mapper.selectUser();
    }

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

    public int delete(int id) {
        return getSqlSession().getMapper(UserMapper.class).delete(id);
    }
}

進行測試

能夠先不配事務測一下,讓其中一個方法錯看看結果

@Test
public void test(){
   ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
   UserMapper mapper = context.getBean("userMapper",UserMapper.class);
   List<User> userList = mapper.selectUser();
    for(User user:userList){
       System.out.println(user); 
    }
   
}

思考問題?

爲何須要配置事務?

  • 若是不配置,就須要咱們手動提交控制事務;
  • 事務在項目開發過程很是重要,涉及到數據的一致性的問題,不容馬虎!
相關文章
相關標籤/搜索