Spring5筆記總結

<!doctype html>Spring5筆記css

 

Spring簡介等(瞭解)

Spring簡介

  • Spring是一個開發源代碼的設計層面的框架,塔解決的是業務邏輯層和其餘各層的鬆耦合問題, 下降耦合度,解耦 ,
  • 所以它將面向對象接口的編程思想貫穿整個系統
  • spring是於2003年興起的一個輕量級的Java開發框架,由Rod Johnson建立,簡單來講,Spring是一個分層的JavaSe/EE full-stack(一站式)輕量級開源框架
  • 它是爲了解決企業應用開發的複雜性而建立的。框架的主要優點之一就是其分層架構, 分層架構容許使用者選擇使用哪個組件,同時爲J2EE應用程序開發提供集成的框架。
  • Spring的核心是控制反轉(lOC) 和麪向切面(AOP) 。簡單來講,Spring是一個分層的JavaSE/EEfull-stack(一站式)輕量級開源框架。
  • 以Ioc(Inversion of Control,控制反轉)和AOP(Aspect Oriented Programming,面向切片編程)爲內核,使用簡單的JavaBean來完成之前只能由EJB(Enterprise Java Beans)完成的工做,取代了臃腫、低效的EJB。

image-20200728140341478

  1. Spring是一個輕量級的開源的javaee框架html

    • 輕量級==大小很小,jar不多,不依賴其餘組件,本身能夠單獨使用
    • 開源==免費
    • 框架==開發更加方便,代碼更加簡潔
  2. Spring目的:能夠解決企業應用開發的複雜性java

  3. String組成部分:核心部分node

    1. IOC --> 反轉控制,new ioc把建立對象過程交給Spring進行管理
    2. AOP --> 面向切面,擴展功能,不修改源代碼進行功能加強

    Spring優勢

    1. 方便解耦,簡化開發,Spring就是一個大工廠,能夠將全部對象建立和依賴關係維護,交給Spring, IOC的做用
    2. 聲明式事務的支持,只須要經過配置就能夠完成對事務的管理,而無需手動編程
    3. AOP編程支持 , Spring提供面向切面編程,能夠方便的實現對程序進行權限攔截,運行監控等功能 (對某個方法加強,代理設計模式,裝飾設計模式)
    4. 方便程序的測試,Spring對Junit4支持,能夠經過註解方便的測試Spring的程序
    5. 方便集成各類優秀的框架,Spring不排除各類優秀的開源框架,其內部提供了對各類優秀的框架(如:Struts2 Hibernate ,Mybaits ,Quartz等)的直接支持
    6. 下降JavaEEAPI的使用難度 ,Spring對JavaEE開發中很是難用的一些API(JDBC,javaMail,遠程調用等),都提供了封裝,使這些API應用難度大大下降

總結一句話:Spring就是一個輕量級的數據反轉(IOC)和麪向切面編程(AOP)的框架mysql

組成

image-20200725140925736

擴展

  • 在Spring的官網有這個介紹:現代化的Java開發!說白了就是基於Spring的開發

image-20200725141003951

  • Spring bootweb

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

    • SpringCloud是基於SpringBoot實現的

由於使用的人多,大多數都在使用SpringBoot進行快速開發,學習SpringBoot的前提,須要徹底掌握Spring及SpringMVC!承上啓下的做用!sql

弊端:發展了過久以後,違背了原來的理念!配置十分繁瑣,人稱:「配置地獄!」數據庫

Spring的IOC核心技術(掌握)

IOC的概念

什麼是IOC?

  • IOC -- Inverse of Control,控制反轉,將對象的建立權力反轉給Spring框架
  • 控制反轉(INversion of Control,縮寫IOC) ,是面向對象編程中的一種設計原則,能夠用來減低計算機代碼之間的耦合度
  • 解決問題:使用IOC能夠解決的程序耦合性高的問題!! Spring的工廠讀取配置文件

image-20200728143515792

IOC程序入門

  1. 建立maven工程,普通Java工程編程

  2. 導入座標

     
     
     
    x
     
     
     
     
    只須要導入一個Spring Context,經過傳遞依賴就能夠把其餘的jar所有導入進來
    <dependencies>
         <!--經過maven窗體依賴,導入依賴的jar包-->
         <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context</artifactId>
              <version>5.0.2.RELEASE</version>
         </dependency>
         <!--junit單元測試-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
         <!--日誌-->
         <dependency>
              <groupId>log4j</groupId>
              <artifactId>log4j</artifactId>
              <version>1.2.12</version>
         </dependency>
         <dependency>
              <groupId>commons-logging</groupId>
              <artifactId>commons-logging</artifactId>
              <version>1.2</version>
         </dependency>
    </dependencies>
     
  3. 在resources目錄下導入log4j.properties

  4. 編寫包,編寫Service接口和實現類

  5. 在resouces目錄下編寫配置文件(推薦名爲:"applicationContext.xml")

    •  
       
       
      xxxxxxxxxx
       
       
       
       
      <?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"
             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/tx
              http://www.springframework.org/schema/tx/spring-tx.xsd
              http://www.springframework.org/schema/aop
              https://www.springframework.org/schema/aop/spring-aop.xsd
              http://www.springframework.org/schema/context
              https://www.springframework.org/schema/context/spring-context.xsd">
       
  6. 編寫測試方法,調方法

    小提示:ApplicationContext工廠類 按住快捷鍵Ctrl+H 能夠查看該類的結構

     
     
     
    xxxxxxxxxx
     
     
     
     
    //先建立Spring的IOC的工廠,加載src目錄下的配置文件,把配置文件中的類建立成對象,存儲到IOC容器中
    ApplicationContext ac = new FileSystemXMlApplicationContext("加載某個磁盤上的文件");
    //ApplicationContext ac = new ClassPathXmlApplicationContext("resources目錄下配置文件");
    //從容器中獲取對象
    UserService us = (UserService)ac.getBean("配置文件bean標籤的id屬性獲取該對象");//注意:強轉,使用接口接收
    //調用對象的方法
    us....
     

 

Spring框架的Bean管理的配置文件方式

  • Bean標籤的屬性

    • id:--> 對象在IOC容器中惟一的名稱,要求編寫的時候是惟一的

    • class: --> 管理的類的全路徑(包名+類名),經過Java反射技術幫助建立實例對象,建立後存到IOC容器當中,經過id來拿對象

    • scope: --> 建立後對象的生命週期(做用範圍)

      • singLeton --> 默認的:單例的,IOC容器中只會存在一個實例的 (通常默認使用)

        • ioc容器中只會存在一個實例的,配置文件一被加載,實例對象就會被建立,生命週期就跟容器是同樣的
      • prototype --> 多例的:(每次獲取 都會建立新的實例對象)

        • 每從IOC容器中獲取對象,纔會建立實例對象.銷燬工做不禁容器負責
       
       
       
      xxxxxxxxxx
       
       
       
       
      //驗證單例和多例的生命週期
      //在service編寫構造方法輸出內容 配置文件修改單例和多例查詢結果 是否先輸出構造參數仍是先輸出從容器中獲取對象以前的內容
       
      • request --> 多列的: request應用在Web項目中,每次HTTP請求都會建立一個新的Bean (基本不用)
      • session --> 多列的: session應用在Web項目中,同一個HTTP Session共享一個Bean (基本不用)
    • init-method ,當bean被載入到容器的時候調用init-method屬性指定的方法

      • 通常會用來完成初始化工做: init-method="service實現類方法"
    • destroy-method ,當bean從容器中刪除的時候調用destroy-method屬性指定的方法

      • 通常會用來完成銷燬工做: destroy-method = "service實現類方法"

        • 注意:多例模式看不見銷燬的工做,由於多例工廠不負責銷燬,多例銷燬是由Java虛擬機完成的
 
 
 
xxxxxxxxxx
 
 
 
 
<bean id="" class="" scope="" init-method="" destroy-method=""></bean>
 

實例化Bean對象的三種方式(瞭解)

框架提供建立bean對象的三種方式,基本上都使用默認方式

  • 默認調用無參構造方式
 
 
 
xxxxxxxxxx
 
 
 
 
<bean id="user" class="...."/>
 
  • 靜態工廠方式
 
 
 
xxxxxxxxxx
 
 
 
 
//建立StaticFactory實體類
//建立靜態create(自定義名User)方法 返回值Service這個類
public class StaticFactory{
     //靜態工廠方式
     public static UserService createUser(){
          sout("經過靜態工廠的方式建立....")
          return new UserServiceImpl();
     }
}
//配置文件中 "經過StaticFactory類的creatrUser這個靜態類獲取的對象"  
//優勢:編寫不少業務邏輯 權限校驗...
<bean id="user" class="包名+StaticFactory類" factory-method="createUser" />
//測試類
...
 
  • 實例化工廠的方式
 
 
 
xxxxxxxxxx
 
 
 
 
//建立Dfactory實體類
//動態工廠方式
public class Dfactory{
     //靜態工廠方式
     public static UserService createUser(){
          sout("實例化工廠的方式建立....")
          return new UserServiceImpl();
     }
}
<bean id="user" class="包名+Dfactory類" factory-method="createUser" factory-bean="dfactory" />;
//測試類
...
 

多配置文件方式

把全部配置都寫在一個配置文件中,太亂,spring支持多配置文件方式

  • 多配置文件方式一:
 
 
 
xxxxxxxxxx
 
 
 
 
//加載多個配置文件
ApplicationContext ac = new ClassPathXmlApplication("applicationContext.xml","application...");//CTRL+P 參數能夠有多個 能夠加載多個配置文件
 
  • 多配置文件方式二:
 
 
 
xxxxxxxxxx
 
 
 
 
<!-- 引入其餘的配置文件 -->
<import resource="applicationContext2.xml"/>
 

IOC技術總結

獲取IOC容器對象

ApplicationContext工廠:建立對象都是由工廠來實現的,讀取配置文件,底層使用反射機制來建立對象

 

ApplicationContext這個接口底層有2個實現類,Ctrl+H查看

  • FileSystemXmlApplicaitonContext("D:\demo\applicaitonContext.xml") = 加載某個磁盤上的配置文件
  • ClassPathXmlApplicaitonContext=類路徑resources目錄下 (基本上都用這個)

使用工廠,獲取IOC容器中的對象 工廠對象.getBean("bean標籤的id別名");

建立Bean對象有三種方式

  1. 默認調用無參構造方式
  2. 靜態工廠方式
  3. 實例化工廠的方式

多配置文件方式

加載多個配置文件,獲取工廠時,參數能夠給多個

或在主配置文件中,增長引入其餘的配置文件

DI依賴注入(掌握)

概念

image-20200729075137420

  • IOC和DI的概念

    • IOC : Inverse of Control ,控制反轉, 將對象的建立權力反轉給Spring !!
    • DI : Dependency Injection ,依賴注入 , 在spring框架負責建立Bean對象時, 動態的將依賴對象注入到Bean組件中

屬性的set方法方式注入

引用類型注入:

 
 
 
xxxxxxxxxx
 
 
 
 
//將dao和service都存放到容器中
//在Service裏面建立Dao成員屬性
//給成員屬性提供一個set方法
//最後修改bean標籤
<bean id="user" class="...">
<property name="這個類的屬性名" ref="引用(bean標籤的id屬性)"/>
</bean>
 

基本類型注入

 
 
 
xxxxxxxxxx
 
 
 
 
//將dao和service都存放到容器中
//在Service裏面建立Dao成員屬性
//給成員屬性提供一個set方法
//最後修改bean標籤
<bean id="user" class="...">
<property name="屬性名" value="成員屬性基本類型的值"/>
</bean>
 
 
 
 
xxxxxxxxxx
 
 
 
 
<!--基本數據類型注入方式-->
<bean id="service" class="cn.dong.service.impl.UserServiceImpl">
     <property name="dao" ref="userDao" />
     <property name="name" value="張三" />
</bean>
 

總結:

  • 只要這個類當中,有其餘類的成員屬性,並提供set方法,就能夠把任何對象注入給這個類

屬性構造方法方式注入值

 
 
 
xxxxxxxxxx
 
 
 
 
//寫實體類 建立構造方法
//配置文件配置bean
<bean id="惟一的名" class="..">
<constructor-arg name="屬性的名稱" value="基本類型" ref="引用類型"/>
<constructor-arg name="屬性的名稱" value="基本類型" ref="引用類型"/>
<constructor-arg name="屬性的名稱" value="基本類型" ref="引用類型"/>
</>
 
 
 
 
xxxxxxxxxx
 
 
 
 
<!--屬性構造器方式注入值-->
<bean id="user" class="cn.dong.domain.User">
     <constructor-arg name="name" value="張三"/>
     <constructor-arg name="age" value="20"/>
</bean>
 

 

數組,集合(List,Set,Map),Properties等的注入

本身通常寫程序用的比較少,可是使用多個框架整合的時候,必定得會寫

 
 
 
xxxxxxxxxx
 
 
 
 
//寫實體類 建立set方法 tostring 數組,集合
//配置文件(給集合屬性注入值)
<bean id="" class="">
     //數組
<property name="屬性名稱">
     <array>//給數組傳值
     <value>張三</value>//基本類型的數組
     <value>李四</value>//基本類型的數組
     //<ref></ref>引用類型的數組
     <array/>  
     </property>
     
     //list集合
     <property name="屬性名稱">
     <list>//給list集合傳值
     <value>張三</value>//泛型爲基本類型
     <value>李四</value>//泛型爲基本類型
     //<ref></ref>泛型爲引用類型
     <list/>  
     </property>
     
     //map集合
     <property name="屬性名稱">
     <map>//給list集合傳值
     <entry key-ref="" value/>//泛型爲引用類型
     <entry key="" value=""/>//泛型爲基本類型
     <entry key-ref="" value=""/>//泛型爲基本類型
     <map/>  
     </property>
     
     //屬性配置文件 實體類 private Properties properties;
     <property>
     <props>
     <prop key="key..."></prop>
     </props>
     </property>
<bean/>
 

DI依賴注入註解

普通數據類型註解

@Value(value = "字符串或數值") //在屬性上增長

 
 
 
xxxxxxxxxx
 
 
 
 
//注意:使用配置文件方式依賴注入,須要提供set方法
//使用註解注入值能夠不須要set方法
@Value("張三")
private String name;
@Value(value="29")
private int age;
 

引用類型註解

 
 
 
xxxxxxxxxx
 
 
 
 
//也不用提供set方法 (經常使用)
@Autowired //按類型(和id沒有任何關係,容器中有對象就自動裝配注入)自動裝配的註解
private User user;
//按id名稱的方式注入 @Qualifier不能單獨使用,須要Autowired一塊兒使用
@Autowired
@Qualifier(value="id名稱")
//這一個頂第二個兩個 (偶爾用)
@Resources(name = "id名稱") //Java提供的註解,按名稱注入對象,屬性名稱是name
 

 

Spring框架開發方式

  • 原來編寫程序流程

    • 需求:編寫service和dao的類, 演示代碼 技術選擇:持久層使用原始的DBC的程序,鏈接池選擇的是Druid鏈接池。 建立maven工程,導入開發的jar包
 
 
 
xxxxxxxxxx
 
 
 
 
//建立普通的Java的maven工程
//引入座標,
<dependencies>
        <!--經過maven窗體依賴,導入依賴的jar包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--junit單元測試-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!--日誌實現-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <!--日誌-->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <!--鏈接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.9</version>
        </dependency>
        <!--MySql驅動包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </dependency>
    </dependencies>;
//建立數據庫 建立表結構 id主鍵 用戶名 money錢 添加3條數據
...;
//新建包,實體類對應數據庫,dao,service
//dao寫一個查詢全部數據的方法
...
//service...
//測試方法
...
 
  • 第二種寫程序的流程IOC開發程序

 
 
 
xxxxxxxxxx
 
 
 
 
//新建編寫spring核心配置文件 log4j配置文件
//配置service和dao的bean標籤 依賴注入...
//dao 鏈接池對象注入到spring 配置鏈接池
<bean id="" class="...">
<property name="driverClassName" value"" />     
<property name="url" value"" />     
<property name="username" value"" />     
<property name="password" value"" />     
</bean>;
//在dao提供DateSource成員屬性 建立set方法 privete DataSource dataSource
<bean id="" class="...">
<property name="dataSource" ref="dataSource" />
</bean>
     
 

 

IOC註解方式(掌握)

IOC非純註解快速入門

IOC註解的方式依賴沒有變化

編寫接口和實體類

在須要管理的類上增長@Compoent註解

 
 
 
xxxxxxxxxx
 
 
 
 
@Component(value = "user")  //組件,做用:把當前類使用IOC容器進行管理,若是沒有指定名稱,默認使用類名,首字母是小寫,或者本身指定名稱
public class UserServiceImpl implents UserService{}
//spring核心配置文件 多配置文件也能夠
<!-- 開啓註解掃描 -->;
<context:component-scan base-package="cn.dong包名"/>
     
 

以上註解@Component... =

經常使用註解

  1. @Component 普通的類
 
 
 
xxxxxxxxxx
 
 
 
 
@Component(value="annotation")
public class AnnotationServiceImpl implements AnnotationService {
    public void showInfo() {
        System.out.println("顯示信息!!");
    }
}
 
  1. @Controller 表現層
  2. @Service 業務層
  3. @Repository 持久層

依賴注入經常使用註解

普通數據類型註解

@Value(value = "字符串或數值") //在屬性上增長

 
 
 
xxxxxxxxxx
 
 
 
 
//注意:使用配置文件方式依賴注入,須要提供set方法
//使用註解注入值能夠不須要set方法
@Value("張三")
private String name;
@Value(value="29")
private int age;
 

引用類型註解

 
 
 
xxxxxxxxxx
 
 
 
 
//也不用提供set方法 (經常使用)
@Autowired //按類型(和id沒有任何關係,容器中有對象就自動裝配注入)自動裝配的註解
private User user;
//按id名稱的方式注入 @Qualifier不能單獨使用,須要Autowired一塊兒使用
@Autowired
@Qualifier(value="id名稱")
//這一個頂第二個兩個 (偶爾用)
@Resources(name = "id名稱") //Java提供的註解,按名稱注入對象,屬性名稱是name
 

對象生命週期(做用範圍)註解

 
 
 
xxxxxxxxxx
 
 
 
 
@Scope(value = "singleton") //默認值,單例的
@Scope(value = "propotype") //多例的
 

初始化方法和銷燬方法註解(瞭解)

 
 
 
xxxxxxxxxx
 
 
 
 
//@PostConstruct 至關於init-method
public void init(){ sout("初始化"); }
//@PreDestroy 至關於destroy-method
public void destroy(){ sout("銷燬"); }
 

註解掃描(組件掃描)

使用以上註解須要在Spring的配置文件進行註解掃描,不然無法注入到IOC容器,報錯空指針異常

 
 
 
xxxxxxxxxx
 
 
 
 
<!--開啓註解掃描(組件掃描)-->
<context:component-scan base-package="cn.dong.service"/>
 

 

IOC純註解的方式(掌握)

純註解的方式是微服務架構開發的主要方式,因此也是很是的重要。純註解的目的是換掉全部的配置文件。可是須要編寫配置類。

編寫配置類SpringConfig,包SpringConfig,替換掉applicationContext.xml配置文件

 
 
 
xxxxxxxxxx
 
 
 
 
@Configuration //聲明當前類是一個配置類
@ComponentScan(value = {"cn.dong","..."})//配置掃描的包
public class ...{}
編寫測試方法
//編寫程序,加載配置類
//建立工廠,加載配置類
ApplicaitonCOntext ac = new AnnotationConfigApplicaitonContext(配置類.class);
ac.getBean(....
 

範例:

 
 
 
xxxxxxxxxx
 
 
 
 
@Service(value="showInfo")//加載類到IOC容器
public class UserServiceImpl implements UserService {//Service業務層
    public void showInfo() {
        System.out.println("業務層顯示信息.....");
    }
}
@Configuration //聲明當前類是一個配置類
@ComponentScan(value="cn.dong") //配置掃描的包
public class SpringConfig {
}
@org.junit.Test
    public void show(){//測試類
        //建立工廠,加載配置類
        ApplicationContext ac = new AnnotationConfigApplicationContext(UserServiceImpl.class);
        //使用工廠獲取對象
        UserServiceImpl service=(UserServiceImpl) ac.getBean("showInfo");
        service.showInfo();
    }
 

引入多個配置類註解

@import註解 String的配置文件能夠分紅多個配置的,編寫多個配置類,用於導入其餘配置類

 
 
 
xxxxxxxxxx
 
 
 
 
@Impoer(value={xxx.class,xxx.class})
public class SrpingConfig{}
 

Bean註解(經常使用)

@Bean 只能寫在方法上,代表使用此方法建立一個對象,對象建立完成保存到IOC容器中,(用於解決鏈接池的對象管理等,不少類都不是本身寫的,只是拿來用不能隨意更改,不能加註解,就得使用bean註解)

 
 
 
xxxxxxxxxx
 
 
 
 
管理IOC,管理鏈接池對象
/**
* 建立鏈接池對象,返回對象,把該方法建立後的對象存入到鏈接池中,使用@Bean註解解決
*/;
@Bean(name="dataSource")//name惟一的
public DataSource source(){
DruidDataSource dataSource = new DruidDataSource();
     dataSource.setUrl("...");
     dataSource.setUsername(".....");
     return dataSource;
}
同等於 Spring配置文件中,配置鏈接池對象;
<bean id="..." ..>
<property name="" value="..."/>
</bean>
 
 
 
 
xxxxxxxxxx
 
 
 
 
持久層;
//Spring模板
@Bean(name="template")
public JdbcTemplate template(){
     //實例化JdbcTemplate對象 Spring模板
     JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
     return template;
}
測試類;
@Test
public void show(){
     //加載配置類,建立工廠
     ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
     //使用工廠對象獲取對象
     JdbcTemplate template =(JdbcTemplate) ac.getBean("template");
     //寫sql語句
     String sql = "select count(*) from user";
     //數據操做
     Integer i=template.queryForObject(sql, Integer.class);
     System.out.println(i);
}
 

 

總結

經常使用註解(類加載到IOC容器)

  1. @Component(value="id名稱") 普通的類
  2. @Controller 表現層
  3. @Service 業務層
  4. @Repository 持久層

這四個註解使用方法,和結果都是同樣的,可是仍是推薦哪一個領域寫哪一個註解!

 

依賴注入註解

  • 基本類型依賴注入

    • @Value("張三")
  • 引用類型依賴注入

    1. @Autowired 自動裝配
    2. @Autowired @Qualifier(value="id名稱") 按id名稱方式注入
    3. @Resources(name = "id名稱") Java提供的註解 也是按id名稱注入

 

對象生命週期註解

  • @Scope(value = "singleton") //默認值,單例的
  • @Scope(value = "propotype") //多例的

初始化和銷燬註解

  • @PostConstruct 至關於init-method
  • @PreDestroy 至關於destroy-method

IOC純註解方式

  • @Configuration //聲明當前類是一個配置類
  • @ComponentScan(basePackages = {「cn.dong或value")//配置掃描的包

引入多個配置類

 
 
 
xxxxxxxxxx
 
 
 
 
@Configuration //聲明配置類
public class SpringConfig{}
@Configuration //聲明配置類
//掃描指定的包結構
@ComponentScan(value="cn.dong")
//引用新的配置類
Import(valueu = {SpringConfig2.class})
public class SpringConfig2{}
 

 

@Bean註解(重要)

只能寫在方法上,代表使用此方法建立一個對象,對象建立完成保存到IOC容器中,(用於解決鏈接池的對象管理等,不少類都不是本身寫的,只是拿來用不能隨意更改,不能加註解,就得使用bean註解)

Spring整合Junit單元測試(掌握)

  • 每次進行單元測試的時候,都須要編寫建立工廠,加載配置文件等代碼,比較繁瑣。Spring提供了整合Junit單元測試的技術,能夠簡化測試開發。下面開始學習該技術。
  • 必須先有Junit單元測試的環境,也就是說已經導入Junit單元測試的jar包。我們已經導入過了。使用的是4.12版本再導入spring-test的座標依賴

快速入門

  1. 檢查jar或座標是否導入,Junit4.12
  2. 導入一個新的座標依賴 」spring整合Junit測試jar包「 ,Spring-test5.0.2

配置文件+註解方式

 
 
 
xxxxxxxxxx
 
 
 
 
<!-- 整合單元測試 -->
<bean id="user" class="cn.dong.User"></bean>
 
 
 
 
xxxxxxxxxx
 
 
 
 
//運行單元測試
@RunWith(value = SpringJunit4ClassRunner.class) 
//加載類路徑下的配置文件
@ConTextConfiguration(value = "classpath:Spring配置文件路徑")
public Class Test{
     //測試哪個對象,就把該對象注入進來,在測試環境下,可使用註解方式注入測試的對象
     @Autowired
     private User user;//依賴注入的測試對象
     
     @Test
     public void show(){
          //...
     }
}
 

純註解方式

 
 
 
xxxxxxxxxx
 
 
 
 
//建立配置類
//聲明配置類
@Configuration
//掃描包結構
@CompoentScan(value = "cn.dong要掃描的路徑")
public class SpringConfig(){
}
//建立測試類
@RunWith(SpringJunit4ClassRunner.class)//運行單元測試
@ContextConfiguration(classes = SpringConfig.class)//加載配置類
public class Test(){
     //按類型依賴注入
     @Autowired
     private User user;
     @Test
     public void show(){
          user...
     }
}
 
 
 
 
xxxxxxxxxx
 
 
 
 
測試類
//運行單元測試
@RunWith(value = SpringJUnit4ClassRunner.class)
//加載路徑下的配置文件
@ContextConfiguration(value="classpath:applicationContext.xml")
public class Test3 {
    //依賴注入的測試對象
    @Autowired
    private User user;
    //Junit測試
    @Test
    public void show(){
        user.setName("顫三");
        System.out.println(user);
    }
}
User實體類
@Component
public class User {
 

總結

爲何要使用Spring整合的Junit單元測試?

  • 每次進行單元測試的時候,都須要編寫建立工廠,加載配置文件等代碼,比較繁瑣。Spring提供了整合Junit單元測試的技術,能夠簡化測試開發。下面開始學習該技術。

測試類增長如下註解

  • @RunWith(value = SpringJUnit4ClassRunner.class)//運行單元測試
  • @ContextConfiguration(value="classpath:applicationContext.xml")//加載路徑下的配置文件
  • @ContextConfiguration(classes=SpringConfig.class)

在測試類中,增長"依賴注入的測試對象(接口)" 直接使用對象調方法便可 (千萬不要忘記: 依賴注入的測試對象 增長@Autowired 自動裝配對象到IOC容器管理)

Spring框架AOP技術

AOP概念的引入

建立maven的普通工程,引入開發座標,跟原來如出一轍

建立包,實體類,業務層,持久層...

導入配置文件

業務層建立2個帳戶,持久層建立1個帳戶

問題來了:業務層若是有一個帳戶建立失敗,就不能給數據庫添加數據,就應該事務回滾,須要事務管理

  • 開啓事務 要用Connection接口,發現dao也須要用到Connection接口,並且還必須用到業務層的Connection接口

    • 第一種方法:方法的參數傳遞,設計以前參數須要一個Connection接口,誰調用誰傳遞 (太麻煩)
    • 第二種方法:線程綁定 能夠從當前線程中拿到直接綁定的Connection (優先使用)
 
 
 
xxxxxxxxxx
 
 
 
 
//業務層
sout("業務層:保存兩個帳號");
//開啓事務 要用Connection接口,發現dao也須要用到Connection接口,並且還必須用到業務層的Connection接口
工具類.startTransaction();
//第一種方法:方法的參數傳遞,設計以前參數須要一個Connection接口,誰調用誰傳遞   (太麻煩)
//第二種方法:線程綁定 能夠從當前線程中拿到直接綁定的Connection (優先使用)
//執行操做
try{
dao.seve(user1);
     //模擬異常
     ...
dao.seve(user2);
//提交事務/回滾事務
工具類.commit();     
} catch(...) {
     //回滾事務打印異常信息
     工具類.rollback();
}finally{
     //關閉資源(歸還鏈接)
     工具類.close();
}
編寫持久層dao;
//獲取到鏈接
Connection conn = 工具類.getConnection();
//編寫sql
...;
//預編譯
PreparedStatement stmt = conn.prepareStatement(sql);
//設置值
stme.setString(1,user.getName());
stmt.setInt(2,user.getMoney());
//執行操做
stmt.executeUpdate();
//關閉資源 conn不能關閉
stmt.close();
 

線程綁定

 
 
 
xxxxxxxxxx
 
 
 
 
業務層
     //DI依賴注入Dao
     UserDaoImpl dao;
public void setDao(UserDaoImpl dao) {
     this.dao=dao;
}
/**
     * 保存2個帳戶
     * @param user1
     * @param user2
     */
public void save(User user1, User user2) {
     //開啓事務:使用第二種方法「線程綁定」
     try {
          AffairUtils.startTransaction();
          //執行操做
          dao.save(user1);
          dao.save(user2);
          //提交事務
          AffairUtils.commit();
     } catch (Exception e) {
          //打印錯誤信息
          e.printStackTrace();
          //提交回滾
          AffairUtils.rollback();
     } finally {
          //歸還鏈接
          AffairUtils.close();
     }
}
持久層;
public void save(User user) throws SQLException {
     //獲取鏈接
     Connection conn=AffairUtils.getConnection();
     //編寫sql
     String sql="insert into `user`.`user` (`name`, `money`) values (?, ?)";
     //預編譯
     PreparedStatement stmt=conn.prepareStatement(sql);
     //設置值
     stmt.setString(1, user.getName());
     stmt.setInt(2, user.getMoney());
     //執行操做
     stmt.executeUpdate();
     //關閉資源
     stmt.close();
}
測試類:
@Test
public void show(){
     //加載配置文件,建立工廠
     ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
     //使用工廠對象獲取對象
     UserService service =(UserService) ac.getBean("userService");
     //建立用戶
     User user1 = new User("熊大",1000);
     User user2 = new User("熊二",2000);
     //保存
     service.save(user1,user2);
}
 

使用到的事務工具類: AffairUtils.java

 

業務層開啓事務 要用Connection接口,發現持久層也須要用到Connection接口,並且還必須用到業務層的Connection接口

  • 第一種方法:方法的參數傳遞,設計以前參數須要一個Connection接口,誰調用誰傳遞 (太麻煩)
  • 第二種方法:線程綁定 能夠從當前線程中拿到直接綁定的Connection (優先使用)

加強方法加強(Jdk動態代理設計模式)

以上代碼的業務層很是繁瑣,在真正開發中,業務層只須要關注業務邏輯,不須要關注其餘,因此就須要進行,業務層的方法加強

  • 加強方法的手段

    • 繼承(加強方法)
    • 裝飾設計模式
    • 動態代理設計模式(推薦使用)
 
 
 
xxxxxxxxxx
 
 
 
 
//建立JdkProxy類
//傳入目標對象,生成該對象的代理對象,返回,對目標對象的方法進行加強
//獲取代理對象,返回,加強目標對象的方法
public static Object getProxy(UserService userService){
     /**
     * 使用Jdk的動態代理生成代理對象
     */
     Object proxy = Proxy.newProxyInstance(類加載器,傳入對象的實現的接口要字節碼對象,回調函數匿名內部類);
     //類加載器 JdkProxy.class.getClassLoader()
     //傳入對象實現了哪些接口的字節碼對象userService.getClass().getInterfaces()
     new InvocationHandler(){//invoke方法參數Object proxy , Method method , Object[] args
          try{
      //開啓事務
          //對目標對象的方法進行加強
          Object result = method.invoke(userService,args);
           //提交事務
          }回滾事務...歸還鏈接
          
          return result;
}
     return proxy;
}
 
 
 
 
xxxxxxxxxx
 
 
 
 
測試類:
@Test
public void show(){
     //其餘代碼省略,請看上方
     //使用工廠對象獲取對象
     UserService service =(UserService) ac.getBean("userService");
    
     //生成代理對象
     Object proxyObj= JdkProxy.getProxy(userService);
     //強轉
     UserService proxy = (UserService) proxyObj;
     //調用代理對象方法(進行保存到數據庫)
     proxy.save(user1,user2);
}
 

範例:

 
 
 
xxxxxxxxxx
 
 
 
 
業務層;
//DI依賴注入Dao
UserDaoImpl dao;
public void setDao(UserDaoImpl dao) {
     this.dao=dao;
}
/**
     * 保存2個帳戶
     * @param user1
     * @param user2
     */
public void save(User user1, User user2) throws SQLException {
     //開啓事務:使用第二種方法「線程綁定」+Jdk動態代理
     dao.save(user1);
     int i = 100/0;
     dao.save(user2);
}
測試類;
@Test
public void show() throws SQLException {
     //加載配置文件,建立工廠
     ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
     //使用工廠對象獲取對象
     UserService service =(UserService) ac.getBean("userService");
     //建立用戶
     User user1 = new User("熊大",1000);
     User user2 = new User("熊二",2000);
     //生成代理對象
     Object proxyObj=JdkProxy.getProxy(service);
     //強轉成Service
     UserService proxy = (UserService)proxyObj;
     //使用代理對象進行保存數據
     proxy.save(user1,user2);
}
 

jdk動態代理類事務管理: JdkProxy.java

AOP的相關概念

寫完以上代碼,又發現一個問題,使用動態代理模式很是繁瑣,若是還要給其餘方法加強,好比:事務管理,日誌的統計,日誌的記錄

因此就可使用SpringAOP這個技術,他能幹什麼: "能夠直接對某個方法進行加強,不用你去繁瑣的寫方法加強"

還有一個問題:動態代理只能加強接口中的方法,沒有接口,還不能加強...

AOP的概述

增長方法,就不用本身寫代理,能夠對某些方法某些個方法進行加強

什麼是AOP的技術?

在軟件業,AOP爲Aspect Oriented Programming的縮寫,意爲:面向切面編程

  • AOP是一種編程範式,隸屬於軟工範疇,指導開發者如何組織程序結構
  • AOP最先由AOP聯盟的組織提出的,制定了-套規範.Spring將AOP思想引入到框架中,必須遵照AOP聯盟的規範
  • 經過預編譯方式或者運行期動態代理實現程序功能的統一維護的一 -種技術
  • AOP是OOP的延續,是軟件開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的- -種衍 生範型
  • 利用AOP能夠對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度下降,提升程序的可重 用性,同時提升了開發的效率

AOP:面向切面編程.(思想--解決OOP遇到一些問題)

AOP採起橫向抽取機制,取代了傳統縱向繼承體系重複性代碼(性能監視、事務管理、安全檢查、緩存)

爲何要學習AOP,能夠在不修改源代碼的前提下,對程序進行加強! !

 

AOP的優點

總結一句話:AOP能夠在不修改源代碼的狀況下,"對某些方法,某些程序進行加強"

優點:

  1. 減小重複的代碼
  2. 提供開發的效率
  3. 維護方便,擴展

AOP底層原理(掌握)

AOP底層實現原理:

  • 底層使用的就是代理技術:

    • JDK的動態代理
    • CGLIB代理技術

爲何Spring框架底層會提供多個代理技術呢?

  • 之後寫程序不必定都是寫接口的,JDK動態代理只能解決接口存在的方法
  • CGLIB代理技術 對類生成代理對象,被代理類是否實現了接口,無所謂 生成class文件,默認繼承了被代理對象(子類加強父類的方法是特別容易的)

Spring框架會自動作一個選擇,當你的程序有沒有接口,默認有:就會用JDK方式加強,若是不是JDK就會使用CGL方式加強

image-20200801141351090

Spring的AOP技術-配置文件

AOP相關的術語(概念)

  1. Joinpoint(鏈接點)所謂鏈接點是指那些被攔截到的點。在spring中,這些點指的是方法,由於spring只支持方法類型的鏈接點

    • Joinpoint"鏈接點"指的是當前類中的全部的方法(如ServiceImpl全部的方法均可以被稱爲:"鏈接點")
  2. Pointcut(切入點) -所謂切入點是指咱們要對哪些oinpoint進行攔截的定義

    • Pointcut "切入點" (編寫切入點表達式) ,程序加強的入口(如: 若是你想加強某個方法,就看你的切入點表達式寫沒寫) -->看切入點表達式來決定 此方法增不加強
  3. Advice(通知/加強)--所謂通知是指攔截到Joinpoint以後所要作的事情就是通知.通知分爲前置通知,後置通知,異常通知,最終通知,環繞通知(切面要完成的功能)

    • Advice(通知/加強) 指 對save方法要進行加強,編寫具體的代碼,編寫事務管理相關的代碼 (要加強的方法,你得寫加強的具體代碼,就寫到通知裏面去)
  4. Target(目標對象)--代理的目標對象

    • 目標對象 --> 你想要加強的方法
  5. Weaving(織入)--是指把加強應用到目標對象來建立新的代理對象的過程

    • 把Advice(通知/加強)的方法加強到目標對象過程就是植入,要把代理的東西織入到目標對象的方法當中 (這個技術是Spring作的)
  6. Proxy (代理) - -個類被AOP織入加強後,就產生一個結果代理類

    • 一個類被AOP織入加強後,就殘生一個結果代理類 (加強完了,返回給你一個代理類,他是一個字節碼文件)
  7. Aspect(切面)--是切入點和通知的結合,之後我們本身來編寫和配置的

    • 很抽象的概念, 切面 = 切入點(開啓加強切面表達式) + 通知(加強的內容)

作AOP開發,編寫的內容

  • 切入點是一個表達式(須要本身編寫)
  • 通知/加強(須要本身來編寫)

AOP入門程序

需求: 業務層對save方法進行加強(不改變代碼對本來打印一條語句改成兩條)

步驟:

  1. 導入新的座標(jar包)

    •  
       
       
      xxxxxxxxxx
       
       
       
       
      <!-- AOP聯盟 -->
      aopalliance  版本1.0
      <!-- aspectj -->
      aspectjweaver 版本1.8.3
      <!-- spring整合 -->
      spring-aspects 版本5.0.2.ReLEASE
       
  2. 引入AOP的XML的名稱空間

     
     
     
    xxxxxxxxxx
     
     
     
     
    xmlns:aop="http://www.springframework.org/schema/aop"
    http://www.springframework.org/schema/aop    https://www.springframework.org/schema/aop/spring-aop.xsd
     
  3. 編寫新的類(切面類MyXMLAspect)

    •  
       
       
      xxxxxxxxxx
       
       
       
       
      /**
      * 自定義切面類 = 切入點(表達式) + 通知組成(加強代碼)
      */
      public class MyXMlAspect{
           //通知
           public void log(){
                //發送郵件/事務管理/記錄日誌
                sout("加強方法執行了");
           }
      }
       
  4. 打開Spring核心配置文件applicationContext.xml

    •  
       
       
      xxxxxxxxxx
       
       
       
       
      <!--配置切面類,把該類交給IOC容器管理-->
      <bean id="xmlAspect" class="...MyXmlAspect"></bean>
      <!--配置AOP的加強-->
      <aop:config>
           <!--用上面的引用id配置切面 = 切入點 + 通知組成-->
      <aop:aspect ref="xmlAspect">
                <!--前置通知: UserServiceImpl的save方法執行前,會加強-->
           <aop:before method="寫切面類通知的方法" pointcut="切入點的表達式execution(public void cn.dong.service.UserServiceImpl.save())"/>
           </aop:aspect>
      </aop:config>
       

切入點的表達式

在配置切入點的時候,須要定義表達式,具體以下:

切入點表達式的格式以下:

  • execution[修飾符] 返回值類型 包名.類名.方法名(參數)

  • 修飾符能夠省略不寫,不是必需要出現的

  • 返回值類型是不能省略不寫的,根據你的方法來編寫返回值。可使用 「 * 」 替代。

  • 包名例如:cn.dong.dao.UserDaoImpl

    • 首先cn是不能省略不寫的,可是能夠*代替
    • 中間的包名可使用*號代替
    • 若是想省略中間的包名可使用..
  • 類名也可使用 * 號代替,也有相似的寫法:*UserDaoImpl

  • 方法也可使用 * 號代替

  • 參數若是是一個可使用 * 號代替,若是想表明任意參數使用 ..

 
 
 
xxxxxxxxxx
 
 
 
 
<aop:before method="切面類方法" phintcut="切入點表達式"/>
<!--
切入點的表達式
 execution(描述想對哪一個類的方法進行加強) 固定寫法
[public] 修飾符(能夠不寫)
void返回值 () * (推薦使用* = 支持返回任意值)
包名+類名 * (所有類或包下的類都加強) 或者類名首位* = (*UserDao)以他開頭
方法 * 也可使用*開頭或者結尾
參數(int,String)或..(推薦使用) 表示任意類型的和個數的參數 = Object..
 
        
通用表達式:execution(public * cn.dong.*.*UserDao.*(..))
注意:加強方法首先找類,找不到不加強方法"並不會報錯,包括返回值填錯和參數"
-->
 

AOP的通知類型

  1. 前置通知: 目標方法執行前,進行加強
  • <aop:before method="..." pointcut="..." /> (開啓事務)
  1. 最終通知: 目標方法執行後成功或者失敗,進行加強 (關閉資源)
  • <aop:after method="..." pointcut="..." />
  1. 後置通知: 目標方法執行成功後,進行加強 (提交事務)
  • <aop:after-returning method="..." pointcut="..." />
  1. 異常通知: 目標方法執行失敗後,進行加強 (回滾事務)
  • <aop:after-throwing method="..." pointcut="..." />
  1. 環繞通知: 目標方法執行先後,均可以進行加強,目標對象的方法須要手動執行

    • <aop:around method="..." pointcut="..." />

    • 直接使用的問題: 目標對象的方法沒有執行,須要手動執行目標對象的方法

      • 在切面類的環繞通知方法增長參數,"ProceedingJoinPoint point"

      • point.procedd(); //讓目標對象的方法去執行 (優勢:這個方法寫在這個位置,以前以後,能夠去完成其餘操做,這個方法自動會拋出異常,也能夠利用異常均可以加強)

      •  
         
         
        xxxxxxxxxx
         
         
         
         
         

總結: 前四個通知能夠一塊兒使用,環繞通知能夠單獨使用,就能夠完成事務管理

 

Spring的AOP技術-註解

AOP註解方式入門程序

配置文件+註解方式

搭建IOC環境...

搭建AOP環境步驟:

  1. 編寫切面類,增長通知方法

  2. @Compoent 把切面類交給IOC容器進行管理

  3. @Aspect //聲明切面類 == <aop:aspect ref="myXmlAspect">

  4. 在log通知方法上增長註解:切入點的表達式

    • @Before(value = "切入點的表達式") //前置通知
    • @After //最終通知
    • @AfterReturning //後置通知
    • @AfterThrowing //異常通知
    • @Around //環繞通知 ,目標對象方法須要手動執行
  5. 開啓AOP自動代理(在Spring核心配置文件配置)

    • <aop:aspectj-autoproxy />

AOP純註解方式

開啓AOP的自動代理 換成 配置類

 
 
 
xxxxxxxxxx
 
 
 
 
@Configuration //配置類
@ComponentScan(value = "掃描下包名") // 掃描包
@EnableAspectJAutoFroxy //開啓自動代理 == (aop:aspectj-autoproxy) />
public class SpringConfig(){}
 

 

總結:

切入點表達式

execution(public * cn.dong..UserDao.*(..))

通知類型註解

  • @Before(value = "切入點的表達式") //前置通知
  • @After //最終通知
  • @AfterReturning //後置通知
  • @AfterThrowing //異常通知
  • @Around //環繞通知 ,目標對象方法須要手動執行

AOP純註解步驟

建立一個配置類,增長如下註解

  • @Configuration //配置類
  • @ComponentScan(value = "掃描下包名") // 掃描包
  • @EnableAspectJAutoFroxy //開啓自動代理

建立切面類增長如下註解:

  • @Compoent //將切面類交給IOC容器管理
  • @Aspect //聲明切面類
  • 在切面類的通知方法上增長通知類型註解...

 

若是不玩純註解配置文件增長如下代碼:

  • <aop:aspectj-autoproxy />

 

總結一句話:AOP能夠在不修改源代碼的狀況下,"對某些方法,某些程序進行加強"

案例

需求:查詢數據庫的所有用戶信息,使用純註解方式

 
 
 
xxxxxxxxxx
 
 
 
 
測試類;
@RunWith(value=SpringJUnit4ClassRunner.class)//運行單元測試
@ContextConfiguration(classes=SpringConfig.class)//掃描配置類
public class Test {
    @Autowired //自動裝配到IOC容器管理
    private UserService service;
    @org.junit.Test
    public void show(){
        service.findAll();
    }
}
 
 
 
 
xxxxxxxxxx
 
 
 
 
userServiceImpl實現類;
@Service
public class UserServiceImpl implements UserService {
    /**
     * 獲取Dao持久層
     */
    @Autowired
    UserDaoImpl dao;
    /**
     * 查詢所有用戶信息
     * @return
     */
    public List<User> findAll() {
        System.out.println(dao.findAll());
        return dao.findAll();
    }
}
 
 
 
 
xxxxxxxxxx
 
 
 
 
spring配置類;
@Configuration //聲明當前是一個配置類
@ComponentScan(value="cn.dong") //配置掃描的包
@EnableAspectJAutoProxy //開啓自動代理
/**
 * Spring配置類
 */
public class SpringConfig {
}
 
 
 
 
xxxxxxxxxx
 
 
 
 
Dao實現類;
/**
 * 持久層
 */
@Repository
public class UserDaoImpl implements UserDao {
     /**
     * 獲取JdbcTemplate對象
     */
     public JdbcTemplate template() {
          //獲取JdbcTemplate對象
          JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
          return template;
     }
     /**
     * 查詢全部用戶
     * @return
     */
     public List<User> findAll() {
          //寫sql語句
          String sql="select * from user ";
          return template().query(sql, new BeanPropertyRowMapper<User>(User.class));
     }
}
 
 
 
 
xxxxxxxxxx
 
 
 
 
切面類(加強方法);
/**
 * 自定義切面類 並聲明切面類將切面類交給IOC容器管理
 */
@Aspect
@Component
public class MyXmlAspect {
    /**
     *後置通知
     */
    @After("execution(public * cn.dong.service.UserService.findAll(..))")
    public void log(){
        System.out.println("查詢了用戶,關閉了程序");
    }
}
 

Spring框架的JDBC模板技術(掌握)

JDBC模板技術概述

什麼模板技術: Spring框架中提供了不少持久層的模板類來簡化編程,使用模板類寫程序會變的簡單

  • template "模板" 發音:譚普累特
  • 都是Spring框架提供XxxTemplate

提供了Jdbc模板,Spring框架提供的

  • JdbcTemplate類,Connection 表示鏈接,事務管理 Statement ResultSet

JDBC的模板類使用

導入座標

 
 
 
xxxxxxxxxx
 
 
 
 
<dependencies>
        <!--經過maven窗體依賴,導入依賴的jar包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--junit單元測試-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!--日誌實現-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <!--日誌接口-->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <!--鏈接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.9</version>
        </dependency>
        <!--MySql驅動包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </dependency>
        <!--spring整合Junit測試jar包-->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--AOP聯盟-->
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <!--aspectj-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
        <!--spring整合-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
      <!--JDBC-->
        <dependency>
            <groupId>maven_repository.org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <!--事務-->
        <dependency>
            <groupId>maven_repository.org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
    </dependencies>
 

編寫開發方式

 
 
 
xxxxxxxxxx
 
 
 
 
使用new對象方式完成;
//建立鏈接池對象 Spring框架內置鏈接池對象
DriverManagerDataSource dataSource = new ...();
//設置四大參數 數據庫 帳號 密碼 包+類
...
//建立對象,提供模板
JdbcTempate template = new JdbcTemplate(鏈接池對象);
 
  • 建立對象,提供模板

    • JdbcTempate template = new JdbcTemplate(鏈接池對象);
  • 方法

    • setDataSource(鏈接池對象) 獲取鏈接池
    • Update 增刪改操做 參數("sql語句",Object可變參數)
 
 
 
xxxxxxxxxx
 
 
 
 
SpringIOC方式編寫程序;
Spring配置文件配置鏈接池和模板;
<!--配置鏈接池-->
     <bean id="dataSource" class="org.springframework.jdbc.datasource .DriverManagerDataSource>
     <property name="driverClassName" value= "..." />
     <property name= "url" value= "..." />
     <property name= "username" value="..." />
     <property name=" password" value="..." />
</bean>
<!--配置jdbc模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource" /></bean>
 
 
 
 
xxxxxxxxxx
 
 
 
 
測試方法;
@RunWith(SpringJunit4ClassRunner.class)
@ContextConfigurgation(value = "classpath:applicationContext.xml")
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
public void run1(){
....
}
 

Spring框架管理開源的鏈接池

配置開源的鏈接池,使用Druid開源的鏈接池,引入座標 druid (德洛依)

druid屬性配置文件: druid.properties

 
 
 
xxxxxxxxxx
 
 
 
 
第一種方式;
<!--引入外部屬性文件-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfiggurer">
<property name="location" value="classpath:druid.properties"/>
</bean>
第二種方式;
<context:property-placeholder location="classpath:druid.properties"/>
     <bean id="dataSource" class="org.springframework.jdbc.datasource .DriverManagerDataSource>
     <property name="driverClassName" value= "${配置文件的key}" />
     <property name= "url" value= "${...}" />
     <property name= "username" value="${...}" />
     <property name=" password" value="${...}" />
</bean>
 

 

增刪改查範例:

修改

 
 
 
xxxxxxxxxx
 
 
 
 
@Test
    public void show2(){
        int i=template.update("update user set name = ?,money = ? where id = ?", "光頭強", 10, 16);
        System.out.println(i);
    }
 

刪除

 
 
 
xxxxxxxxxx
 
 
 
 
@Test
    public void show3(){
        template.update("delete from user where id = ?",16);
    }
 

查詢: 根據主鍵查詢數據

 
 
 
xxxxxxxxxx
 
 
 
 
//queryForObject("sql語句",RowMapper<T>實體類封裝查詢數據 , Obect..數據)
User user = jdbcTemplate.queryForObject("select * from user where id=?",new BeanMapper());
//新建實體類,用來進行數據封裝的 實現RowMapper<T要封裝的類型>{
class BeanMapper implements RowMapper<Account>{
//建立user對象
          User user = new User();
          //封裝數據
          account.setId(resultSer.getInt("數據庫對應的值id"));
          account.setName(resultSer.getInt("數據庫對應的值name"));
          account.setMoney(resultSer.getInt("數據庫對應的值money"));
          reretn user;
}
}
查詢:查詢所有()
//queryForObject("sql語句",RowMapper<T>實體類封裝查詢數據 , Obect..數據)
User user = jdbcTemplate.queryForObject("select * from user",new BeanMapper());
 

 

 
 
 
xxxxxxxxxx
 
 
 
 
/**
     * 根據主鍵查詢用戶信息
     */
@Test
public void show3(){
     User user=template.queryForObject("select * from user where id = ?", new BeanPropertyRowMapper<User>(User.class),1);
     System.out.println(user);
}
/**
     * 查詢所有用戶信息
     */
@Test
public void show4(){
     List<User> list=template.query("select * from user", new BeanPropertyRowMapper<User>(User.class));
     System.out.println(list);
}
 

轉帳案例

業務層: 轉帳方法,三個參數: ont付款人 in收款人 money金額

持久層: 付款 收款 2個方法 各爲2個參數

 
 
 
xxxxxxxxxx
 
 
 
 
測試類;
@Autowired
private UserService service;
@Test
public void show(){
     service.pay(2,1,500);
}
業務層;
public class UserServiceImpl implements UserService {
    //獲取dao
    private UserDao dao;
    public void setDao(UserDao dao) {
        this.dao=dao;
    }
    public void pay(int out, int in, int money) {
        //收錢
        dao.inMoney(in,money);
        //給錢
        dao.outMoney(out,money);
    }
}
持久層;
/**
     * 獲取IOC容器中的JdbcTemplate對象
     */
private JdbcTemplate template;
public void setTemplate(JdbcTemplate template) {
     this.template=template;
}
/**
     * 發款
     * @param out
     * @param money
     */
public void outMoney(int out, int money) {
     template.update("update user set money = money - ? where id = ?",money,out);
}
/**
     * 收款
     * @param in
     * @param money
     */
public void inMoney(int in, int money) {
     template.update("update user set money = money + ? where id = ?",money,in);
}
 

注意事項:

發現了一個問題 , 持久層的JdbcTemplate的模板 成員屬性還有set方法,

每一次有個新的dao類,就得寫一次jdbc模板和set方法,太繁瑣,太麻煩 ,

這時候能夠定義一個父類,把模板寫到父類當中 ,

可是我們不用管,Spring框架已經幫忙寫好了直接繼承就好

  • extends JbdcDaoSupport "這個模板類裏面有JdbcTemplate ,也有set方法find修飾的因此你不能寫直接用父類的便可 " 使用方法以下:
 
 
 
xxxxxxxxxx
 
 
 
 
public void outMoney(int out, int money) {
     this.getJdbcTemplate().update("update user set money = money - ? where id = ?",money,out);
}
 
 
 
 
xxxxxxxxxx
 
 
 
 
配置文件;
模板類能夠不用配置
在配置dao時,直接依賴注入鏈接池
<bean id="userDao" class="cn.dong.dao.UserDaoImpl">
<property name="別名" ref="鏈接池引入id(別名)"/>
</bean>
 

範例:

 
 
 
xxxxxxxxxx
 
 
 
 
/**
     * 收款
     * @param in
     * @param money
     */
    public void inMoney(int in, int money) {
        this.getJdbcTemplate().update("update user set money = money + ? where id = ?",money,in);
    }
<!--引入外部屬性文件-->
    <context:property-placeholder location="classpath:druid.properties"/>
    <!--配置Druid鏈接池-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${driverClassName}" />
        <property name="url" value="${url}" />
        <property name="username" value="root" />
        <property name="password" value="${password}" />
    </bean>
    <!--配置實體類加載到IOC容器-->
    <bean id="service" class="cn.dong.service.impl.UserServiceImpl">
        <property name="dao" ref="dao"/>
    </bean>
    <bean id="dao" class="cn.dong.dao.impl.UserDaoImpl" >
        <!--依賴注入鏈接池-->
        <property name="dataSource" ref="dataSource" />
    </bean>;
 

 

Spring的事務管理(掌握)

Spring框架的事務管理相關的類和API

 
 
 
xxxxxxxxxx
 
 
 
 
1. PlatformTransactionManager接口     -- 平臺事務管理器.(真正管理事務的類)。該接口有具體的實現類,根據不一樣的持久層框架,須要選擇不一樣的實現類!
2. TransactionDefinition接口          -- 事務定義信息.(事務的隔離級別,傳播行爲,超時,只讀)
3. TransactionStatus接口              -- 事務的狀態
4. 總結:上述對象之間的關係:平臺事務管理器真正管理事務對象.根據事務定義的信息TransactionDefinition 進行事務管理,在管理事務中產生一些狀態.將狀態記錄到TransactionStatus中
5. PlatformTransactionManager接口中實現類和經常使用的方法
    1. 接口的實現類
        * 若是使用的Spring的JDBC模板或者MyBatis框架,須要選擇DataSourceTransactionManager實現類
        * 若是使用的是Hibernate的框架,須要選擇HibernateTransactionManager實現類
    2. 該接口的經常使用方法
        * void commit(TransactionStatus status) 
        * TransactionStatus getTransaction(TransactionDefinition definition) 
        * void rollback(TransactionStatus status) 
6. TransactionDefinition
    1. 事務隔離級別的常量
        * static int ISOLATION_DEFAULT                  -- 採用數據庫的默認隔離級別
        * static int ISOLATION_READ_UNCOMMITTED 
        * static int ISOLATION_READ_COMMITTED 
        * static int ISOLATION_REPEATABLE_READ 
        * static int ISOLATION_SERIALIZABLE 
    2. 事務的傳播行爲常量(不用設置,使用默認值)
        * 先解釋什麼是事務的傳播行爲:解決的是業務層之間的方法調用!!
        * PROPAGATION_REQUIRED(默認值) -- A中有事務,使用A中的事務.若是沒有,B就會開啓一個新的事務,將A包含進來.(保證A,B在同一個事務中),默認值!!
        * PROPAGATION_SUPPORTS          -- A中有事務,使用A中的事務.若是A中沒有事務.那麼B也不使用事務.
        * PROPAGATION_MANDATORY         -- A中有事務,使用A中的事務.若是A沒有事務.拋出異常.
        * PROPAGATION_REQUIRES_NEW(記)-- A中有事務,將A中的事務掛起.B建立一個新的事務.(保證A,B沒有在一個事務中)
        * PROPAGATION_NOT_SUPPORTED     -- A中有事務,將A中的事務掛起.
        * PROPAGATION_NEVER             -- A中有事務,拋出異常.
        * PROPAGATION_NESTED(記)     -- 嵌套事務.當A執行以後,就會在這個位置設置一個保存點.若是B沒有問題.執行經過.若是B出現異常,運行客戶根據需求回滾(選擇回滾到保存點或者是最初始狀態)
 

TransactionDefinition接口事務的傳播行爲: 解決業務層方法相互調用,事務傳播問題 (使用默認值)

image-20200802152751941

聲明式事務管理代碼編寫:

步驟一: 配置平臺事務管理器

 
 
 
xxxxxxxxxx
 
 
 
 
<!--配置平臺事務管理器-->
<bean id="transactionMavager" class="DataSourceTransactionMavager">
<!--依賴注入鏈接池-->
     ...
</bean>
 

步驟二: 配置平臺事務通知

 
 
 
xxxxxxxxxx
 
 
 
 
<!--引入tx名稱空間-->
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
<!--配置平臺事務通知(沒有本身編寫切面類,通知方法也是很多本身編寫的,Spring框架提供的)-->
<tx:advice id="txAdvisor" transaction-manager="transactionManager">
     <!--對方法進行加強,設置隔離級別,傳播行爲,超時的時間-->
<tx:mehod name="方法名" isolation="DEFAULT默認" propagation="REQUIRED默認" read-only="是不是隻讀的事務(查詢的時候能夠設置爲只讀) timeout="事務超時時間(-1永久)"/><tx:mehod name="方法名"/><!--能夠配置多個--?
</tx:advice>
 

步驟三: 配置AOP的加強 (Spring框架提供的系統通知)

 
 
 
xxxxxxxxxx
 
 
 
 
<!--配置AOP的加強-->
<aop:config>
     <!--Spring框架提供的系統通知,使用advisor標籤-->
<aop:advisor advice-ref="txAdvice事務通知id" pointcut="execution(public * 包名+類名+方法名(..))" />
</aop:config>
 

範例:

 
 
 
xxxxxxxxxx
 
 
 
 
<!--引入外部屬性文件-->
<context:property-placeholder location="classpath:druid.properties"/>
<!--配置Druid鏈接池-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
     <property name="driverClassName" value="${driverClassName}" />
     <property name="url" value="${url}" />
     <property name="username" value="root" />
     <property name="password" value="${password}" />
</bean>
<!--配置實體類加載到IOC容器-->
<bean id="service" class="cn.dong.service.impl.UserServiceImpl">
     <property name="dao" ref="dao"/>
</bean>
<bean id="dao" class="cn.dong.dao.impl.UserDaoImpl" >
     <!--依賴注入鏈接池-->
     <property name="dataSource" ref="dataSource" />
</bean>
<!--配置平臺事務管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     <!--依賴注入鏈接池-->
     <property name="dataSource" ref="dataSource" />
</bean>
<!--配置平臺事務通知-->
<tx:advice id="txAdvisor" transaction-manager="transactionManager">
     <!--對方法進行加強,設置隔離級別,傳播行爲,超時時間...-->
     <tx:attributes>
          <tx:method name="pay" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1"/>
     </tx:attributes>
</tx:advice>
<!--配置AOP的加強-->
<aop:config>
     <!--Spring框架提供的系統通知,使用advisor標籤-->
     <aop:advisor advice-ref="txAdvisor" pointcut="execution(public * cn.dong.service.impl.UserServiceImpl.pay(..))" />
</aop:config>
 

配置文件+註解,聲明式事務管理

配置文件能夠更改的地方有: 配置事務的通知 , 和配置AOP的加強(這些均可以省略不寫使用註解代替)

步驟一: 開啓註解的掃描

 
 
 
xxxxxxxxxx
 
 
 
 
在Spring配置開啓註解的掃描
<context:component-scan base-package="xn.dong"/>
給持久層和業務層增長註解,把類交給IOC容器進行管理
在業務層 依賴注入dao 使用@Autowired註解
持久層依賴注入 jdbcTemplate (但在以前先在配置文件中將jdbcTemplate放到IOC容器管理)
開啓事務對註解的支持
<tx:annotation-driven transaction-mavager="transactionManager" />
在Service增長註解@Transactional = 對Service的全部方法進行事務管理 也能夠增長到方法中 對當前方法進行事務管理
@Transactional(isolation = Isolation.DEFAULT) //設置隔離級別 (能夠點進註解查看屬性)
 

範例:

 
 
 
xxxxxxxxxx
 
 
 
 
<!--引入外部屬性文件-->
    <context:property-placeholder location="classpath:druid.properties"/>
    <!--配置Druid鏈接池-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${driverClassName}" />
        <property name="url" value="${url}" />
        <property name="username" value="root" />
        <property name="password" value="${password}" />
    </bean>
    <!--註解掃描-->
    <context:component-scan base-package="cn.dong" />
    <!--加載到IOC容器管理-->
    <bean id="template" class="org.springframework.jdbc.core.JdbcTemplate" >
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!--開啓事務對註解的支持-->
    <tx:annotation-driven transaction-manager="transactionManager" />
    <!--配置平臺事務管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--依賴注入鏈接池-->
        <property name="dataSource" ref="dataSource" />
    </bean>
dao;@Repository("dao")
@Autowired
private JdbcTemplate template;
service;@Service("service")
@Autowired
private UserDao dao;
 

 

純註解,聲明式事務管理

 
 
 
xxxxxxxxxx
 
 
 
 
建立配置類,
掃描包
鏈接池
使用@Bean 註解 //把鏈接池保存到IOC容器中
模板對象
使用@Bean   //把JdbcTemplate保存到IOC容器中
@Resource  //不只能夠做用在屬性上,也能夠做用在方法上
平臺事務管理器
使用@Bean   //把JdbcTemplate保存到IOC容器中
@Resource  //不只能夠做用在屬性上,也能夠做用在方法上
開啓事務註解
@EnableTransactionManagement //開啓事務註解
 

範例:

 
 
 
xxxxxxxxxx
 
 
 
 
配置類;
/**
 * Spring配置類
 */
@Configuration //聲明配置類
@ComponentScan(value="cn.dong") //掃描包
@EnableTransactionManagement
public class SpringConfig {
    /**
     *   建立鏈接池對象
     */
    @Bean("dataSource")
    public DataSource dataSource(){
        //建立鏈接池對象,Spring框架內置了鏈接池
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        //設置四個參數
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai");
        dataSource.setUsername("root");
        dataSource.setPassword("accp");
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        return dataSource;
    }
    /**
     * 建立Spring模板的JdbcTemplate對象
     * @return
     */
    @Bean
    @Resource(name="dataSource")
    public JdbcTemplate jdbcTemplate(){
        //建立JdbcTemplate對象
        JdbcTemplate template=new JdbcTemplate();
        //存放鏈接到JdbcTemplate
        template.setDataSource(dataSource());
        return template;
    }
    /**
     * 建立平臺事務管理對象
     * @return
     */
    @Bean
    @Resource(name="dataSource")
    public PlatformTransactionManager createTransactionManager(){
        DataSourceTransactionManager manager = new DataSourceTransactionManager(dataSource());
        return manager;
    }
}
@Service("service")
@Transactional(isolation=Isolation.DEFAULT) //對此類中全部方法都增長事務管理
public class UserServiceImpl implements UserService {
    //獲取dao
    @Autowired
    private UserDao dao;
    public void pay(int out, int in, int money) {
        //收錢
        dao.inMoney(in,money);
       int i = 100/0;
        //給錢
        dao.outMoney(out,money);
    }
}
測試類;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=SpringConfig.class)
public class Demo {
    @Autowired
    private UserService service;
    @Test
    public void show(){
        service.pay(2,1,100);
    }
}
 

 

總結:

相關文章
相關標籤/搜索