天天看點

Spring學習筆記Spring

Spring

1、簡介

  • 曆史:在2002年,首次推出了Spring架構的雛形:interface21架構。而Spring架構就是以interface21架構為基礎,經過重新設計并不斷豐富其内涵,在2004年3月24日釋出了1.0正式版
  • 創始人:Rod Johnson,著名作者,專業是音樂學而非計算機
  • 理念:整合了現有的技術架構,使現有的技術更加容易使用,本身是一個大雜燴
  • 優點:
    • 開源的免費的架構(容器)
    • 輕量級的、非入侵式的架構
    • 最大特點是控制反轉(IOC)、面向切面程式設計(AOP)
    • 支援事務處理和架構整合
  • 弊端:發展了太久之後,違背了原來的理念,配置十分繁瑣
  • 組成:
    Spring學習筆記Spring
  • 拓展
    • Spring官網的介紹:現代的Java開發,其實就是基于Spring的開發
Spring學習筆記Spring
  • Spring Boot
    • 一個快速開發的腳手架,基于SpringBoot可以快速的開發單個微服務
    • 約定大于配置
    • 大多數公司使用,學習前提是完全掌握Spring及SpringMVC
  • Spring Cloud
    • 基于SpringBoot實作

官網:https://spring.io/projects/spring-framework#overview

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

官方下載下傳位址:https://repo.spring.io/release/org/springframework/spring/

Github:https://github.com/spring-projects/spring-framework

2、IOC

2.1 理論推導

問題:在之前的業務中,使用者的需求可能會影響原代碼,需要根據使用者的需求去修改原代碼,如果程式代碼量非常大,修改一次的成本代價非常昂貴

改進:使用set接口

private UserDao userDao;

public void setUserDao(UserDao userDao){
    this.userDao = userDao;
}
           
  • 改進之前,程式主動建立對象,控制權在程式員手上
  • 改進之後,程式不再具有主動性,變成了被動地接受對象
  • 這種思想從本質上解決了問題,程式員不用再管理對象的建立,可以更加專注于業務實作,系統耦合性大大降低。這是IOC原型

2.2 本質

控制反轉(IoC)是一種設計思想,DI(依賴注入)是實作IoC的一種方法。在沒有IoC的程式中使用面向對象程式設計,對象的建立與對象間的依賴關系完全寫死在程式中,對象的建立由程式自己控制;IoC是将對象的建立轉移給第三方。通俗來說,控制反轉是一種通過描述(XML或者注解)并通過第三方去生産或擷取特定對象的方式。在Spring中實作控制反轉的是IoC容器,其實作方式是依賴注入(Dependency Injection,DI)

Spring學習筆記Spring
  • 配置:IoC是Spring架構的核心内容,使用多種方式完美的實作了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置實作IoC
    • 兩種配置方式的差別:采用XML方式配置Bean的時候,Bean的定義資訊是和實作分離的,而采用注解的方式可以把兩者合為一體,Bean的定義資訊直接以注解的形式定義在實作類中,進而達到了零配置的目的
  • 原理:Spring容器在初始化時先讀取配置檔案,根據配置檔案或中繼資料建立與組織對象存入容器中,程式使用時再從IoC容器中取出需要的對象

3、HelloSpring

直接給類成員變量指派測試:

  1. 導入Spring所需依賴
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.6.RELEASE</version>
</dependency>
           
  1. 建立實體類,編寫get、set方法
public class Hello {
    private String str;

    public void setStr(String str){
        this.str=str;
    }

    public String getStr(){
        return str;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}
           
  1. 編寫bean.xml檔案,頭檔案在官方文檔複制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="hello" class="com.Nana.pojo.Hello">
        <property name="str" value="hello"></property>
    </bean>

</beans>
           
  1. 測試
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Hello hello = (Hello)classPathXmlApplicationContext.getBean("hello");
        System.out.println(hello);
    }
}
           

先注冊再引用核心代碼:

<bean id="mysqlImpl" class="com.Nana.dao.UserDaoMysql"></bean>
<bean id="oracleImpl" class="com.Nana.dao.UserDaoOracle"></bean>

<bean id="UserServiceImpl" class="com.Nana.service.UserServiceImpl">
    <property name="userDao" ref="mysqlImpl"></property>
</bean>
           
  • ref:引用Spring容器中建立好的對象
  • value:适用于基本資料類型,給成員變量指派

ClassPathXmlApplicationContext和ApplicationContext的繼承關系:

Spring學習筆記Spring

4、IOC建立對象的方式

  1. 無參構造(預設)
<bean id="user" class="com.Nana.pojo.User">
    <property name="name" value="海燕醬"></property>
</bean>
           
  1. 有參構造
    • 使用下标指派
    <bean id="user" class="com.Nana.pojo.User">
        <constructor-arg index="0" value="海燕醬"></constructor-arg>
    </bean>
               
    • 使用類型指派(不建議使用)
    <bean id="user" class="com.Nana.pojo.User">
        <constructor-arg type="java.lang.String" value="海燕醬"></constructor-arg>
    </bean>
               
    • 通過參數名指派(推薦)
    <bean id="user" class="com.Nana.pojo.User">
        <constructor-arg name="name" value="海燕醬"></constructor-arg>
    </bean>
               

注意:在配置檔案加載的時候,容器中管理的對象就已經初始化了

5、Spring配置

5.1 别名

作用:添加了别名,可以使用别名擷取到對象

5.2 Bean的配置

屬性:

  • id:唯一辨別符,相當于對象名
  • class:bean對象所對應的全限定名:包名+類名
  • name:别名,比alias更進階,可以同時取多個别名
<bean id="user" class="com.Nana.pojo.User" name="u2,u3,u4">
    <property name="name" value="海燕醬"></property>
</bean>
           

5.3 import

作用:将多個配置檔案倒入合并為一個,一般用于團隊開發使用,可直接使用總的配置

6、依賴注入

  • 本質:Set注入
    • 依賴:bean對象的建立依賴于容器
    • 注入:bean對象中的所有屬性由容器來注入

6.1 普通方式

  • 構造器注入

    詳見4

  • 普通值注入
  • Bean注入
<bean id="address" class="com.Nana.pojo.Address"></bean>

<bean id="student" class="com.Nana.pojo.Student">
    <property name="address" ref="address"></property>
</bean>
           
  • 數組注入
<property name="books">
    <array>
        <value>紅樓夢</value>
        <value>西遊記</value>
        <value>水浒傳</value>
        <value>三國演義</value>
    </array>
</property>
           
  • List注入
<property name="hobbys">
    <list>
        <value>聽歌</value>
        <value>敲代碼</value>
        <value>看電影</value>
    </list>
</property>
           
  • Map注入
<property name="card">
    <map>
        <entry key="身份證" value="111111111111111"></entry>
        <entry key="銀行卡" value="222222222222222"></entry>
    </map>
</property>
           
  • Null注入
<property name="wife">
    <null/>
</property>
           
  • Properties注入
<property name="info">
    <props>
        <prop key="username">root</prop>
        <prop key="password">123456</prop>
    </props>
</property>
           
  • Set注入
<property name="games">
    <set>
        <value>LOL</value>
        <value>COC</value>
        <value>BOB</value>
    </set>
</property>
           

6.2 擴充方式

使用p命名空間和c命名空間注入:

  • p标簽:property縮寫,作用是給成員變量指派
  • c标簽:constructor-arg縮寫,作用是給有參構造函數傳參

使用:

  1. 在Mapper中導入xml限制
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
           
  1. 使用
<bean id="user" class="com.Nana.pojo.User" p:name="海燕醬" p:age="21"></bean>
<bean id="user2" class="com.Nana.pojo.User" c:name="海燕醬" c:age="21"></bean>
           

6.3 Bean的作用域

Spring學習筆記Spring
  1. 單例模式(Spring的預設模式),在通過相同name多次取bean的時候取到的是同一個
  1. 原型模式,每次從容器中get時都會産生一個新對象
  1. 其餘的四個隻能在web開發中使用到

7、Bean的自動裝配

解釋:

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

Spring三種裝配方式:

  • 在xml中顯示地配置
  • 在java中顯示地配置
  • 隐式地自動裝配bean

7.1 ByName和ByType自動裝配

byName:自動在容器的上下文中查找和自己對象set方法後面值對應的beanid

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

<bean id="people" class="com.Nana.pojo.People" autowire="byName">
    <property name="name" value="海燕醬"></property>
</bean>
           

byType:自動在容器上下文中查找和自己對象屬性類型相同的bean

<bean class="com.Nana.pojo.Cat"></bean>
<bean class="com.Nana.pojo.Dog"></bean>

<bean id="people" class="com.Nana.pojo.People" autowire="byType">
    <property name="name" value="海燕醬"></property>
</bean>
           
  • byName的使用需要保證所有bean的id唯一,并且這個bean需要和自動注入屬性的set方法的值一緻
  • byType的使用需要保證所有bean的class唯一,并且這個bean需要和自動注入屬性的類型一緻

7.2 使用注解進行自動裝配

  • jdk1.5開始支援注解,Spring2.5開始支援注解

注解使用:

  1. 導入context限制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
</beans>
           
  1. 配置注解支援(重要,不能遺忘這一步)

@Autowired和**@Qualifier**

  • 可以直接在屬性上使用,也可以在set方法上使用
  • 使用此注解可以不用編寫set方法,前提是這個自動裝配的屬性在IoC容器中存在,且符合名字byName
//如果顯示地定義了required屬性為false,說明這個對象可以為空,否則不能為空
@Autowired(required = false)
String name;
@Autowired
Cat cat;
Dog dog;
           

注意:如果@AUtowired自動裝配的環境比較複雜,自動裝配無法通過一個注解@Autowired完成的時候,可以使用@Qualifier(value = “xxx”)去配置Autowired的使用,指定一個唯一的bean對象注入

@Autowired
@Qualifier(value = "cat111");
Cat cat;
           

@Resource

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

@Autowired和@Resource相同點和差別:

  • 相同點:都是用來自動裝配的,都可以放在屬性字段上
  • 不同點:
    • @Autowired通過byType的方式實作,而且要求這個對象存在
    • @Resource通過byName的方式實作,如果根據名字無法找到,就通過byType實作,如果兩種方式都找不到就報錯
    • 執行順序不同:@Autowired通過byType方式實作,@Resource預設通過byName的方式實作

8、使用注解開發

注意:

  • 在Spring4之後,要使用注解開發,必須保證aop包的導入
Spring學習筆記Spring
  • 使用注解需要導入context限制,增加注解支援
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/beans/spring-context.xsd">
    
    <context:annotation-config/>
</beans>
           

@Component和@Value

@Component
public class User {
    public String name;

    @Value("海燕醬")
    public void setName(String name){
        this.name=name;
    }
}
           

@Repository、@Service、@Controller

@Component衍生注解,在web開發中,會按照mvc三層架構分層

  • dao【@Repository】
  • service【@Service】
  • controller【@Controller】

這四個注解功能一樣,都是代表将某個類注冊到Spring中,裝配Bean

@Scope

@Component
@Scope("prototype")
public class User {
    public String name;

    @Value("海燕醬")
    public void setName(String name){
        this.name=name;
    }
}
           

xml和注解:

  • xml更加萬能,适用于任何場合,維護簡單友善;注解不是自己的類使用不了,維護相對複雜
  • xml是用來管理bean的,注解隻負責完成屬性的注入
  • 在使用注解過程中需要注意的是:必須讓注解生效,需要開啟注解的支援

9、使用Java的方式配置Spring

  1. 寫實體類,給實體類成員變量注入值
//@Component注解表明這個類被Spring接管了,注冊到了容器中
@Component
public class User {
    private String name;

    public String getName() {
        return name;
    }

    @Value("海燕醬")
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}
           
  1. 編寫配置類
//@Configuration注解表明目前類是配置類,作用類似于之前寫過的beans.xml
@Configuration
//@ComponentScan注解自動掃描指定包下所有使用@Service,@Component,@Controller,@Repository的類并注冊
@ComponentScan
//@Import注解可導入單個元件或者多個元件,id預設為全類名
@Import(NanaConfig.class)
public class NanaConfig {
    
    //@Bean注解作用是注冊一個bean,相當于之前寫的一個bean标簽
    //方法名相當于bean标簽中的id屬性
    //方法的傳回值相當于bean标簽中的class屬性
    @Bean
    public User user(){
        return new User();
    }
}
           
  1. 編寫測試類
//如果完全使用了配置類方式去做,就隻能通過AnnotationConfig上下文來擷取容器,通過配置類的class對象加載
ApplicationContext context = new AnnotationConfigApplicationContext(NanaConfig.class);
User user = context.getBean("user", User.class);
System.out.println(user.getName());
           

這種純Java配置方式,在SpringBoot中随處可見

10、代理模式

  • 使用:SpringAOP的底層
  • 分類:靜态代理和動态代理
Spring學習筆記Spring

10.1 靜态代理

角色分析:

  • 抽象角色:一般會使用角色或者抽象類來解決
  • 真實角色:被代理的角色
  • 代理角色:代理真實角色後,一般會做一些附屬操作
  • 客戶:通路代理對象的人

優點:

  • 可以使真實角色的操作更加純粹,不用去關注一些公共的業務
  • 公共業務交給代理角色,實作了業務的分工
  • 公共業務發生擴充的時候,友善集中管理

缺點:

  • 一個真實角色就會産生一個代理角色,代碼量會翻倍,開發效率會變低

租客、房東、中介案例:

//租房接口
public interface Rent {
    public void rent();
}
           
//房東要出租房子
public class Host implements Rent{
    @Override
    public void rent() {
        System.out.println("房東要出租房子!");
    }
}
           
//中介在租房子同時作惡一些附加操作
public class Proxy implements Rent{
    private Host host;

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

    public void rent(){
        seeHouse();
        host.rent();
        hetong();
        fare();
    }

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

    public void hetong(){
        System.out.println("簽租賃合同");
    }

    public void fare(){
        System.out.println("收中介費");
    }
}
           
//租客租房子
public class Client {
    public static void main(String[] args) {
        Host host = new Host();
        Proxy proxy = new Proxy(host);
        proxy.rent();
    }
}
           

10.2 加深了解

Spring學習筆記Spring

實踐代碼:

//Service接口層
public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}
           
//Service接口實作層
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("查詢了一個使用者");
    }
}
           
//代理層,主要為了增加輸出日志功能
public class UserServiceProxy {
    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("[Debug]使用了"+msg+"方法");
    }
}
           
//通路代理層
public class Client {
    public static void main(String[] args) {
        UserserviceImpl userService = new UserserviceImpl();
        UserServiceProxy proxy = new UserServiceProxy();
        proxy.setUserService(userService);
        proxy.query();
    }
}
           

10.3 動态代理

  • 和靜态代理相同及不同點:
    • 相同點:和靜态代理角色一樣
    • 代理類是動态生成的,不是直接寫好的
  • 分類:基于接口的動态代理和基于類的動态代理
    • 基于接口:JDK
    • 基于類:cglib
    • java位元組碼實作:javasist
  • 使用到的類:
    • Proxy:代理
    • InvocationHandler:調用處理程式
  • 優點:
    • 可以使真實角色的操作更加純粹,不用去關注一些公共的業務
    • 公共業務交給代理角色,實作了業務的分工
    • 公共業務發生擴充的時候,友善集中管理
    • 一個動态代理類代理的是一個接口,一般就是對應的一類業務
    • 一個動态代理類可以代理多個類,隻要是實作了同一個接口

使用:

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


    public Object invoke(Object proxy, Method method, Object[] args) throws  Throwable{
        log(method.getName());
        //執行target接口中的args方法,傳回執行結果
        Object result = method.invoke(target, args);
        return result;
    }

    public void log(String msg){
        System.out.println("執行了"+msg+"方法");
    }
}
           
public class Client {
    public static void main(String[] args) {
        //建立一個真實角色
        UserserviceImpl userService = new UserserviceImpl();

        //建立一個不存在的動态代理
        ProxyInvocationHandler pih = new ProxyInvocationHandler();

        //設定要代理的對象
        pih.setTarget(userService);

        //生成一個真實的代理類
        UserService proxy = (UserService)pih.getProxy();
        proxy.query();
    }
}
           

11、AOP

11.1 什麼是AOP

AOP為Aspect Oriented Programming的縮寫,意為:面向切面程式設計,通過預編譯方式和運作期間動态代理實作程式功能的統一維護的一種技術。AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring架構中的一個重要内容,是函數式程式設計的一種衍生範型。利用AOP可以對業務邏輯的各個部分進行隔離,進而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。
Spring學習筆記Spring

11.2 AOP在Spring中的作用

1. 提供聲明式事務

2. 允許使用者自定義切面

3. 可以在不改變原有代碼的情況下,去增加新的功能

主要組成部分:

  • 橫切關注點:跨越應用程式多個子產品的方法或功能,即與業務邏輯無關,但是需要關注的部分。如:日志、安全、緩存、事務等等
  • 切面(Aspect):橫切關注點被子產品化的特殊對象,是一個類
  • 通知(Advice):切面必須要完成的工作,是類中的一個方法
  • 目标(Target):被通知的對象
  • 代理(Proxy):向目标對象應用通知之後建立的對象
  • 切入點(PointCut):切面通知執行的"地點"
  • 連接配接點(JointPoint):與切入點比對的執行點
Spring學習筆記Spring

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

Spring學習筆記Spring

11.3 使用Spring實作AOP

導入AOP所需依賴:

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

測試環境搭建:

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void select();
}
           
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 select() {
        System.out.println("查詢了一個使用者");
    }
}
           
public class BeforeLog implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被執行了");
    }
}
           
public class AfterLog implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("執行了"+method.getName()+"方法,傳回結果為:"+returnValue);
    }
}
           
<?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">

    <bean id="userService" class="com.Nana.service.UserServiceImpl"></bean>
    <bean id="beforelog" class="com.Nana.Beforelog.Log"></bean>
    <bean id="afterLog" class="com.Nana.log.AfterLog"></bean>
</beans>
           
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applictaionContext.xml");
        //注意點:動态代理代理的是接口
        UserService userService = (UserService)context.getBean("userService");
        userService.select();
    }
}
           

實作方式一:使用Spring的API接口

<aop:config>
    <aop:pointcut id="pointcut" expression="execution(* com.Nana.service.UserServiceImpl.*(..))"/>
    <aop:advisor advice-ref="beforelog" pointcut-ref="pointcut"></aop:advisor>
    <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>
</aop:config>
           

實作方式二:使用自定義類

public class DiyPointCut {
    public void before(){
        System.out.println("========方法執行前========");
    }
    public void after(){
        System.out.println("========方法執行後========");
    }
}
           
<bean id="diy" class="com.Nana.diy.DiyPointCut"></bean>

<aop:config>
    <aop:aspect ref="diy">
        <aop:pointcut id="point" expression="execution(* com.Nana.service..UserServiceImpl.*(..))"></aop:pointcut>
        <aop:before method="before" pointcut-ref="point"></aop:before>
        <aop:after method="after" pointcut-ref="point"></aop:after>
    </aop:aspect>
</aop:config>
           

實作方式三:使用注解

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

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

    @Around("execution(* com.Nana.service.UserServiceImpl.*(..))")
    public void arround(ProceedingJoinPoint jp) throws Throwable{
        System.out.println("'環繞前");
        Signature signature = jp.getSignature();
        System.out.println("signature:"+signature);

        Object proceed = jp.proceed();
        System.out.println("環繞後");
        System.out.println(proceed);
    }
}
           
<bean id="annotationPointCut" class="com.Nana.diy.AnnotationPointCut"/>
<!--開啟注解支援-->
<aop:aspectj-autoproxy/>
           

execution表達式:

execution(* com.loongshawn.method.ces….(…))
Spring學習筆記Spring

12、整合Mybatis

12.1 測試環境搭建

  1. 導入相關jar包:junit、mybatis、mysql、spring、aop、mybatis-spring
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.2</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.1.9.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.1.9.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.13</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.2</version>
</dependency>
           
  1. 導入靜态資源過濾
<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>
           
  1. 編寫核心配置檔案
<?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>
    <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=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper class="com.Nana.mapper.UserMapper"/><!--注意這裡是/做分隔符-->
    </mappers>
</configuration>
           
  1. 編寫pojo實體類
public class User {
    private int id;
    private String name;
    private String pwd;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
           
  1. 編寫Mapper查詢語句
<?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.Nana.mapper.UserMapper">
    <select id="selectUser" resultType="com.Nana.pojo.User">
        select * from user
    </select>
</mapper>
           
  1. 測試
public void test() throws IOException {
    InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
    SqlSession sqlSession = sessionFactory.openSession();

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

12.2 整合方式一

  1. 編寫資料源配置dao.xml,專注于資料庫基本操作
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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">

    <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=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

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

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
</beans>
           
  1. 編寫總配置applictaionContext.xml,專注于注冊Mapper和引用其他配置
<?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">

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

    <bean id="userMapper" class="com.Nana.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"></property>
    </bean>
</beans>
           
  1. 編寫接口實作類,專注于業務實作
public class UserMapperImpl implements UserMapper{
    private SqlSessionTemplate sqlSession;

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

    @Override
    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}
           
  1. 測試
public void test() throws IOException {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
    for (User user : userMapper.selectUser()) {
        System.out.println(user);
    }
}
           

注意:在mybatis核心配置檔案中可以隻進行取别名typealiases和設定settings

12.3 整合方式二

在整合方式一基礎上做了一定簡化,可以直接注入SqlSessionFactory

  1. 在12.2步驟2代碼基礎上添加
<bean id="userMapper2" class="com.Nana.mapper.UserMapperImpl2">
    <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
           
  1. 在12.2步驟3代碼基礎上改進
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
    @Override
    public List<User> selectUser() {
        return getSqlSession().getMapper(UserMapper.class).selectUser();
    }
}
           

13、Spring中的事務管理

事務重要性:

  • 如果不配置事務,可能存在資料送出不一緻的情況
  • 如果不在Spirng中配置聲明式事務,就需要在代碼中手動配置事務
  • 事務在項目的開發中十分重要,涉及到資料的一緻性和完整性

事務管理分類:

  • 聲明式事務:使用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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd">

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    
	<!--先根據資料源獲得一個事務管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--具體事務通知-->
    <tx:advice id="txAdvice" 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="query" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--設定事務通知切入點以及切入事務-->
    <aop:config>
        <aop:pointcut id="txPoint" expression="execution(* com.Nana.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
    </aop:config>
</beans>
           

Spring中七種事務傳播行為:

Spring學習筆記Spring