Spring基礎入門

一、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="//www.springframework.org/schema/beans"
       xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
       xmlns:context="//www.springframework.org/schema/context"
       xsi:schemaLocation="//www.springframework.org/schema/beans //www.springframework.org/schema/beans/spring-beans.xsd //www.springframework.org/schema/context //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過來的!
  • 尊重每一位學習知識的人,同時也尊重每一位分享知識的人。
  • 你的點贊與關注,是我努力前行的無限動力。
Tags: