Spring基礎入門

2022-07-21 21:00:13

一、Spring瞭解

Spring:程式設計師們的春天

  • Spring主要技術是IOC、AOP兩個大概念
  • 它是輕量級的,每個jar包就1M ~ 3M 左右,所以速度快
  • 面向介面程式設計:降低了耦合度
  • 面向切面程式設計:增加了靈活性
  • 不排斥其它框架,可以和任何框架整合到一起

二、IOC入門

2.1 IOC概念

IOC:控制反轉,是物件導向程式設計中的一種設計原則,可以用來減低計算機程式碼之間的耦合度。其中最常見的方式叫做依賴注入,還有一種方式叫「依賴查詢」。
IOC是一種設計思想,其實我們在學習Spring的時候,應該把注意力放在Spring的設計方式上,為什麼要這麼設計,這麼設計的思想是什麼。
控制反轉:原本我們程式設計師需要自己new Student一個物件,但是現在反轉了,我們將new Student這種操作交給Spring容器去處理,這就是控制反轉,以後不需要我們手動的去new物件了
依賴注入:依賴注入就是我們在建立了物件以後,肯定要給物件的屬性賦值啊,這種賦值的操作就是依賴注入,只是我們的賦值方式和以往略有不同。

2.1 建立物件

  • 使用xml方式,通過bean標籤來建立物件
<bean id="stu" class="com.meteor.pojo.Student"></bean>
這就相當於我們的 Student stu = new Student(); 已經建立出來了物件
id:是物件的名稱
class:是物件類
//這就相當於我們把物件交給了spring容器處理,想用的時候就去容器種拿
  • 我們來取一下物件,看看是如何使用的
//1.通過讀取組態檔中的bean標籤資訊,已經建立出了物件 相當於Student stu = new Student();
//當讀取applicationContext.xml組態檔資訊時,會將其所有bean標籤的物件都建立出來
ApplicationContext cpx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.通過bean標籤中的id拿到物件
Student stu = (Student) cpx.getBean("stu");

2.2 使用setter賦值

  • 我們的類物件,必須有set()方法
  • 必須擁有無參構造方法
  • 我們用的標籤是property

簡單型別的注入:

<!-- 建立學生物件 -->
    <bean id="stu" class="com.meteor.pojo.Student">
        <property name="name" value="張三"/>
        <property name="age" value="21"/>
    </bean>

參照型別的注入:

<!-- 建立學生物件 -->
    <bean id="stu" class="com.meteor.pojo.Student">
        <property name="name" value="張三"/>
        <property name="age" value="21"/>
        <property name="school" ref="sch"/>
     </bean>

    <bean id="sch" class="com.meteor.pojo.School">
        <property name="name" value="hljdx"/>
        <property name="address" value="hlj"/>
    </bean>
// 我們將Student、School兩個物件都交給了spring容器管理,而參照型別的注入方式是通過ref屬性,將school這個物件傳到student裡面

2.3 使用構造方法注入

  • 必須擁有構造方法,你構造方法是幾個引數,注入就幾個引數
  • 無需強制set()方法
  • 我們用的標籤是constructor-arg
<!-- 建立學生物件 -->
<bean id="school" class="com.meteor.pojo2.School">
    <--!--> name是構造方法的名稱 </--!-->
    <constructor-arg name="name" value="hljdx"/>
    <constructor-arg name="address" value="hlj"/>
</bean>
  • 也可以通過引數下標來注入
<bean id="stu" class="com.meteor.pojo2.Student">
    <constructor-arg index="0" value="hljdx"/>
    <constructor-arg index="1" value="20"/>
    <constructor-arg index="2" ref="school"/>
</bean>

2.4 參照型別自動注入

剛剛我們已經介紹了參照型別通過ref屬性注入,但是還可以通過另兩種方式

byName:按照變數名稱注入,spring容器會根據你原本類中的參照型別 public School school 這個school名稱,自動去xml檔案中搜尋有沒有這個同名id,如果有則進行注入。

byType:按照變數型別注入,spring容器會自動尋找School型別的class,一種型別只有一個物件。

  • java類中的成員變數的型別與xml檔案中bean物件的型別一樣

  • java類中的成員變數的型別與xml檔案中bean物件的是父(java)子(xml)型別

  • 若子類父類別用預設得名稱,則父類別先注入。子類的構造方法會預設呼叫父類別無參構造方法,清空資料嘛,然後再呼叫自己的構造方法。若子類父類別改名了,則按名稱注入。

  • java類中的成員變數的型別與xml檔案中bean物件的型別是介面(java)與實現類

2.5 使用註解一體化IOC

//使用註解必須在xml檔案中設定註解掃描器
 <context:component-scan base-package="com.meteor.pojo3"/>

控制反轉

  • 我們使用xml時通過bean標籤來建立物件,現在使用註解來代替
@Component
public class Student {
// 當我們在類上加入這個註解的時候,就相當於將物件放入了spring容器進行管理。但是此時並沒有進行賦值操作,
如果我們不加入名稱,則預設使用的是駝峰命名法

//並且Spring建立的物件是單例模式,無論我們使用多少次都是相同的物件

@Component: 可以建立任意物件

@Controller: 專門建立控制器的物件(Servlet),接受使用者請求返回處理結果給使用者端

@Service: 專門用來建立業務邏輯物件,存取資料層,處理完畢後返回給介面層

@Repository: 用來建立資料存取層的物件,負責增刪改查


依賴注入

@Value: 給簡單型別注入值

@Autowired: 使用型別注入值,從整個Bean工廠中搜尋同源型別的物件,進行注入

@Autowired + @Qualifier : 使用名稱注入值,如果單獨使用Qualifier 是不會注入進來值得

@Resource: 自動注入,我個人挺喜歡用這個先按名稱匹配,再按型別匹配Bean。


三、AOP入門

3.1 AOP概念

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

AOP面向切面程式設計,一般將公用的程式碼放入到切面中,例如紀錄檔、事務等等,減少了冗餘的程式碼,降低了程式的耦合度。

3.2 常用AOP通知

  • 切面:就是將重複的、可複用的程式碼提取出來

  • 連線點:就是目標方法,因為我們需要知道是在目標方法 前 切面還是 後 切面

  • 切入點:多個連線點構成了切入點

  • 通知:指定切入時機

  • 在Advice的時間,在Pointcut的位置,執行Aspect

  • @Before:前置通知,在目標方法之前執行,只能拿到目標方法的簽名

  • @AfterRetunring:後置通知,在目標方法後執行,可以修改目標方法的返回值

  • @Around:環繞通知,這個最厲害,相當於前兩者的結合,但是略有不同

  • @After:最終通知,無論程式掛沒掛,這個都必須執行,一般用於釋放資源

  • @AfterThrowing:異常通知,在目標方法執行發生了異常的時候,執行這個通知、

  • 公式:execution(存取許可權、返回型別、方法宣告(引數))

  • 在xml檔案中加入切面的註解

<aop:aspectj-autoproxy/>

3.3 Before前置通知

@Aspect
public class MyAspect {
    //定義方法,表示切面的具體功能
    /*
        前置通知方法的定義
        1)方法是public
        2)方法是void
        3)方法名稱自定義
        4)方法可以有引數,如果有是JoinPoint
        @Before:前置通知
            屬性:value切入點表示式,表示切面的執行位置。
                在這個方法時,會同時執行切面的功能
            位置:在方法的上面
        特點:
        1)執行時間:在目標方法之前先執行的
        2)不會影響目標方法的執行
        3)不會修改目標方法的執行結果
     */
    @Before(value = "execution(public void com.meteor.service.impl.SomeServiceImpl.doSome(String, Integer))")
    public void myBefore() {
        System.out.println("前置通知,切面的功能在目標方法之前執行" + new Date());
    }
}
//可以擁有一個方法引數JoinPoint jp,用來獲取方法簽名

3.4 @AfterRetunring後置通知

//通過returning來指定方法返回值得名稱,必須與接收名稱相同
//如果說我們傳的是基本型別則無法改變結果,如果傳的是參照型別則可以通過值進行修改。
@AfterReturning(value = "execution(* *..SomeServiceImpl.doOther(..))",returning = "res")
public void myAfterReturning(Object res) {
    System.out.println("後置通知,在目標方法後執行的。" + res);
}

3.5 @Around環繞通知(最重要)


* *..service.*.*(..)
代表任意許可權方法下的 任意包下的 service包 下的 任意類中的任意方法的任意引數

// 返回型別推薦使用Object或者*
@Aspect
public class MyAspect {
    @Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("執行了myAround" + pjp);

        //執行目標方法 ProceedingJoinPoint表示 doFirst
        Object proceed = pjp.proceed(); // method.invoke(),表示執行doFirst()方法本身
        //return "HelloAround,不是目標方法的執行結果";
        //返回目標方法執行結果,沒有修改的
        return proceed;
    }
}
  • 如果你細心的去將所有通知一起加入進來,那麼你會發現其實並不是@After 通知在最後一個執行,這應該是官方經過了很多的測試選擇的最佳方案吧。

3.6 Pointcut

  • 這個就是將我們的切入點表示式起一個別名。

四、Spring繼承MyBatis

4.1 xml的設定

  • 首先我們需要在mapper.xml中進行設定
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 讀取屬性檔案jdbc.properties -->
    <context:property-placeholder location="jdbc.properties"/>
    <!-- 建立資料來源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <!-- 設定SqlSessionFactoryBean類 -->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 設定資料來源-->
        <property name="dataSource" ref="dataSource"/>
        <!-- 設定MyBatis核心組態檔-->
        <property name="configLocation" value="SqlMapConfig.xml"/>
        <!-- 註冊實體類的別名-->
        <property name="typeAliasesPackage" value="com.meteor.pojo"/>
    </bean>
    <!-- 註冊mapper.xml檔案-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.meteor.mapper"/>
    </bean>
</beans>
  • 設定事務處理
使用 @Transactional(propagation=)
<!-- 事務處理 -->
    <!-- 1.新增事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 因為事務必須關聯資料庫處理,所以要設定資料來源 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 新增事務的註解驅動 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
  • JDBC:Connection conn.commit(); conn.rollback();

  • MyBatis:SqlSession sqlSession.commit(); sqlSession.rollback();

  • Hibernate:Session session.commit(); session.rollback();

  • 事務管理器用來生成相應技術的連線 + 執行語句的物件

  • 如果使用MyBatis框架,必須使用DataSourceTransactionManager類完成處理

  • MySQL:mysql預設的事務處理級別是'REPEATABLE-READ',也就是可重複讀

4.2 Spring事務傳播特性

  • 多個事務之間的合併、互斥等都可以通過設定事務的傳播特性來解決

  • PROPAGATION_REQUIRED:必被包含事務(增刪改必用)

  • PROPAGATION_REQUIRED_NEW:自己新開事務,不管之前是否有事務

  • PROPAGATION_SUPPORTS:支援事務,如果加入的方法有事務,則支援事務,如果沒有,不單開事務

  • PROPAGATION_NEVER:不能執行中事務中,如果包在事務中,拋異常

  • PROPAGATION_NOT_SUPPORTED:不支援事務,執行在非事務的環境

  • 專案中的所有事務,必須新增到業務邏輯層上。

五、結尾

  • 這些只是Spring的基礎入門知識,畢竟筆者也僅僅二刷,待筆者閉關修煉,後續會繼續更新原始碼底層知識。
  • 對於Spring內容就總結這麼多,若想深入學習等待後續更新。
  • 我將會繼續更新關於Java方向的學習知識,感興趣的小夥伴可以關注一下。
  • 文章寫得比較走心,用了很長時間,絕對不是copy過來的!
  • 尊重每一位學習知識的人,同時也尊重每一位分享知識的人。
  • 你的點贊與關注,是我努力前行的無限動力。