1. 程式人生 > 實用技巧 >SSM工作流程與原理詳解

SSM工作流程與原理詳解

自學ssm->springboot->springcloud,所以很多東西會用但理解較淺,所以現在從最開始的ssm開始進行對原理以及執行過程的整理知識歸納,若有錯誤感謝指正。

Spring

Spring執行原理

1. Data Access/Integration(資料訪問/整合)

資料訪問/整合層包括 JDBC、ORM、OXM、JMS 和 Transactions 模組,具體介紹如下。

  • JDBC 模組:提供了一個 JDBC 的抽象層,大幅度減少了在開發過程中對資料庫操作的編碼。
  • ORM 模組:對流行的物件關係對映 API,包括 JPA、JDO、Hibernate 和 iBatis 提供了的整合層。
  • OXM 模組:提供了一個支援物件/XML 對映的抽象層實現,如 JAXB、Castor、XMLBeans、JiBX 和 XStream。
  • JMS 模組:指 Java 訊息服務,包含的功能為生產和消費的資訊。
  • Transactions 事務模組:支援程式設計和宣告式事務管理實現特殊介面類,併為所有的 POJO。

2. Web 模組

Spring 的 Web 層包括 Web、Servlet、Struts 和 Portlet 元件,具體介紹如下。

  • Web 模組:提供了基本的 Web 開發整合特性,例如多檔案上傳功能、使用的 Servlet 監聽器的 IoC 容器初始化以及 Web 應用上下文。
  • Servlet模組:包括 Spring 模型—檢視—控制器(MVC)實現 Web 應用程式。
  • Struts 模組:包含支援類內的 Spring 應用程式,集成了經典的 Struts Web 層。
  • Portlet 模組:提供了在 Portlet 環境中使用 MVC實現,類似 Web-Servlet 模組的功能。

3. Core Container(核心容器)

Spring 的核心容器是其他模組建立的基礎,由 Beans 模組、Core 核心模組、Context 上下文模組和 Expression Language 表示式語言模組組成,具體介紹如下。

  • Beans 模組:提供了 BeanFactory,是工廠模式的經典實現,Spring 將管理物件稱為 Bean。
  • Core 核心模組:提供了 Spring 框架的基本組成部分,包括 IoC 和 DI 功能。
  • Context 上下文模組:建立在核心和 Beans 模組的基礎之上,它是訪問定義和配置任何物件的媒介。ApplicationContext 介面是上下文模組的焦點。
  • Expression Language 模組:是執行時查詢和操作物件圖的強大的表示式語言。

4. 其他模組

Spring的其他模組還有 AOP、Aspects、Instrumentation 以及 Test 模組,具體介紹如下。

  • AOP 模組:提供了面向切面程式設計實現,允許定義方法攔截器和切入點,將程式碼按照功能進行分離,以降低耦合性。
  • Aspects 模組:提供與 AspectJ 的整合,是一個功能強大且成熟的面向切面程式設計(AOP)框架。
  • Instrumentation 模組:提供了類工具的支援和類載入器的實現,可以在特定的應用伺服器中使用。
  • Test 模組:支援 Spring 元件,使用 JUnit 或 TestNG 框架的測試。

Spring IoC容器的基本概念

2.基本講解

在傳統方法中,Java物件需要呼叫另外一個Java物件時(如①呼叫②),呼叫者(①)通常採用“new”被呼叫者(②)來建立物件,這種方式會增加呼叫者和被呼叫者之間的耦合性。

當Spring框架出現後,物件例項不再由呼叫者來建立,即不通過直接new被呼叫者來建立物件,而是交給Spring容器來建立。這時候呼叫者的程式將不再進行直接控制,而實轉交給了Spring容器,這就是Spring的控制反轉。

從Spring容器角度出發,Spring容器負責將被依賴物件賦值給呼叫者的成員變數,相當於呼叫者注入它所有依賴的例項,這就是Spring的依賴注入。

舉一個很直白的例子:海綿寶寶做出第一個美味蟹黃堡,當海綿寶寶想做多幾個蟹黃堡(呼叫者)時就得參照第一個蟹黃堡(被呼叫者)來進行製作。一旦第一個蟹堡王丟了或者變味了,他後面就沒辦法做出一模一樣的美味蟹黃堡(耦合度高),所以這時候海綿寶寶把第一個蟹黃堡放到一個按照配方運轉的製造機器裡(Spring容器),往後創造新的蟹黃堡都交給製造機來控制(Spring的控制反轉)。

2.通過Web服務其方式例項化ApplicationContext容器(最常用的方式)

Spring IoC容器的設計主要是基於BeanFactory和ApplicationContext兩個介面,而ApplicationContext是BeanFactory的子介面

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    id="WebApp_ID" version="3.1">
    <display-name>StudentShopping</display-name>
    <!-- needed for ContextLoaderListener -->
    <!-- Spring載入ApplicationContext容器 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    <!-- Bootstraps the root web application context before servlet initialization -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

web.xml中ContextLoaderListener的作用:就是啟動Web容器時,讀取在contextConfigLocation中定義的xml檔案,自動裝配ApplicationContext的配置資訊,併產生WebApplicationContext物件,然後將這個物件放置在ServletContext的屬性裡,這樣我們只要得到Servlet就可以得到WebApplicationContext物件,並利用這個物件訪問spring容器管理的bean。

依賴注入的理解

以下只進行簡單程式碼講解,關於spring依賴注入型別具體實現可參考這篇文章:https://blog.csdn.net/lyc_liyanchao/article/details/82428726

而這兩種注入可以分別用兩種註解來實現一個是 @Autowired 和 @Resource :@Autowired 可以用作構造注入 /@Resource 用作setter注入。

  • @Autowired註解是按照型別(byType)裝配依賴物件,預設情況下它要求依賴物件必須存在,如果允許null值,可以設定它的required屬性為false。
  • @Resource有兩個重要的屬性:name和type,而Spring將@Resource註解的name屬性解析為bean的名字,而type屬性則解析為bean的型別。所以,如果使用name屬性,則使用byName的自動注入策略,而使用type屬性時則使用byType自動注入策略。

另外在構造方法注入中,<constructor-arg>元素【以下黃色標註部分】表示構造方法的一個引數,且使用時不區分順序。當構造方法的引數出現混淆、無法區分時,可以通過<constructor-arg>元素的index屬性指定該引數的位置索引,索引從0開始。<constructor-arg>元素還提供了type屬性用來指定引數的型別,避免字串和基本資料型別的混淆。這也解釋了為什麼@Autowired 可用作構造注入

public class Car {
    
    private String brand;
    private String corp;
    private double price;
    private int maxSpeed;
    public Car(String brand, String corp, double price) {
        this.brand = brand;
        this.corp = corp;
        this.price = price;
    }
    public Car(String brand, String corp, int maxSpeed) {
        this.brand = brand;
        this.corp = corp;
        this.maxSpeed = maxSpeed;
    }
    @Override
    public String toString() {
        return "Car [brand=" + brand + ", corp=" + corp + ", price=" + price
                + ", maxSpeed=" + maxSpeed + "]";
    }
}
<?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:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
    
    <bean id="car" class="com.auguigu.spring.beans.Car">
        <constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
        <constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
        <constructor-arg value="30000" type="int"></constructor-arg>
    </bean>
    
    <bean id="car2" class="com.auguigu.spring.beans.Car">
        <constructor-arg value="BMW" type="java.lang.String"></constructor-arg>
        <constructor-arg value="BeiJing" type="java.lang.String"></constructor-arg>
        <constructor-arg value="300.00" type="double"></constructor-arg>
    </bean>
</beans>

MyBatis

MyBatis執行流程

MyBatis執行流程解析

  1. 讀取 MyBatis 配置檔案:mybatis-config.xml 為 MyBatis 的全域性配置檔案,配置了 MyBatis 的執行環境等資訊,例如資料庫連線資訊。
  2. 載入對映檔案。對映檔案即 SQL 對映檔案,該檔案中配置了操作資料庫的 SQL 語句,需要在 MyBatis 配置檔案 mybatis-config.xml 中載入。mybatis-config.xml 檔案可以載入多個對映檔案,每個檔案對應資料庫中的一張表。
  3. 構造會話工廠:通過 MyBatis 的環境等配置資訊構建會話工廠 SqlSessionFactory。
  4. 建立會話物件:由會話工廠建立 SqlSession 物件,該物件中包含了執行 SQL 語句的所有方法。
  5. Executor 執行器:MyBatis 底層定義了一個 Executor 介面來操作資料庫,它將根據 SqlSession 傳遞的引數動態地生成需要執行的 SQL 語句,同時負責查詢快取的維護。
  6. MappedStatement 物件:在 Executor 介面的執行方法中有一個 MappedStatement 型別的引數,該引數是對對映資訊的封裝,用於儲存要對映的 SQL 語句的 id、引數等資訊。【MappedStatement維護了一條<select|update|delete|insert>節點的封裝】
    <select id="selectAuthorLinkedHashMap" resultType="java.util.LinkedHashMap">
        select id, username from author where id = #{value}
    </select>
  7. 輸入引數對映:輸入引數型別可以是 Map、List 等集合型別,也可以是基本資料型別和 POJO 型別。輸入引數對映過程類似於 JDBC 對 preparedStatement 物件設定引數的過程。
  8. 輸出結果對映:輸出結果型別可以是 Map、 List 等集合型別,也可以是基本資料型別和 POJO 型別。輸出結果對映過程類似於 JDBC 對結果集的解析過程。

MyBatis核心元件

  1. SqlSessionFactoryBuilder(構造器):它會根據配置或者程式碼來生成 SqlSessionFactory,採用的是分步構建的 Builder 模式。【SqlSessionFactoryBuilder 的作用在於建立 SqlSessionFactory,建立成功後,SqlSessionFactoryBuilder 就失去了作用,所以它只能存在於建立 SqlSessionFactory 的方法中,而不要讓其長期存在】
  2. SqlSessionFactory(工廠介面):依靠它來生成 SqlSession,使用的是工廠模式。【SqlSessionFactory 可以被認為是一個數據庫連線池,它的作用是建立 SqlSession 介面物件。因為 MyBatis 的本質就是 Java 對資料庫的操作,所以 SqlSessionFactory 的生命週期存在於整個 MyBatis 的應用之中,所以一旦建立了 SqlSessionFactory,就要長期儲存它,直至不再使用 MyBatis 應用,所以可以認為 SqlSessionFactory 的生命週期就等同於 MyBatis 的應用週期。我們往往希望 SqlSessionFactory 作為一個單例,讓它在應用中被共享。所以說SqlSessionFactory 的最佳作用域是應用作用域。】
  3. SqlSession(會話):一個既可以傳送 SQL 執行返回結果,也可以獲取 Mapper 的介面。在現有的技術中,一般我們會讓其在業務邏輯程式碼中“消失”,而使用的是 MyBatis 提供的 SQL Mapper 介面程式設計技術,它能提高程式碼的可讀性和可維護性。【SqlSessionFactory 相當於資料庫連線池,那麼 SqlSession 就相當於一個數據庫連線(Connection 物件),你可以在一個事務裡面執行多條 SQL,然後通過它的 commit、rollback 等方法,提交或者回滾事務。它應該存活在一個業務請求中,處理完整個請求後,應該關閉這條連線,讓它歸還給 SqlSessionFactory,否則資料庫資源就很快被耗費精光,系統就會癱瘓,所以用 try...catch...finally... 語句來保證其正確關閉。
  4. SQL Mapper(對映器):MyBatis 新設計存在的元件,它由一個 Java 介面和 XML 檔案(或註解)構成,需要給出對應的 SQL 和對映規則。它負責傳送 SQL 去執行,並返回結果。【Mapper 是一個介面,它由 SqlSession 所建立,所以它的最大生命週期至多和 SqlSession 保持一致,儘管它很好用,但是由於 SqlSession 的關閉,它的資料庫連線資源也會消失,所以它的生命週期應該小於等於 SqlSession 的生命週期。Mapper 代表的是一個請求中的業務處理,所以它應該在一個請求中,一旦處理完了相關的業務,就應該廢棄它。】

為什麼要利用Spring來整合MyBatis?

1、MyBatis與Spring的整合步驟

<!--配置資料來源-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/springtest?seUnicode=true&amp;characterEncoding=utf-8" />
    <property name="username" value="root" />
    <property name="password" value="1128" />
    <!-- 最大連線數 -->
    <property name="maxTotal" value="30"/>
    <!-- 最大空閒連線數 -->
    <property name="maxIdle" value="10"/>
    <!-- 初始化連線數 -->
    <property name="initialSize" value="5"/>
</bean>
<!-- 配置SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 引用資料來源元件 -->
    <property name="dataSource" ref="dataSource" />
    <!-- 引用MyBatis配置檔案中的配置 -->
    <property name="configLocation" value="classpath:mybatis-config.xml" />
</bean>

由上面可以得知,我們都知道Spring在整合Mybatis的時候都會配置一個SqlSessionFactoryBean物件來生成一個SqlSessionFactory,而這個SqlSessionFactory就是作為SqlSession(資料庫會話)的關鍵部分,那麼Spring又怎麼把這個物件與DAO介面類關聯放在mapperRegistry

@Mapper
public interface AdminDao {
    public List<Auser> login(Auser auser);
}

AdminMapper.xml檔案

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- com.dao.AdminDao對應Dao介面 -->
<mapper namespace="com.dao.AdminDao">
    <!-- 查詢使用者資訊 -->
    <select id="login"  resultType="Auser" parameterType="Auser">
        select * from ausertable where aname=#{aname} AND  apwd=#{apwd}
    </select>
</mapper>

使用 Spring 管理 MyBatis 資料操作介面的方式有多種,其中最常用、最簡潔的一種是基於 MapperScannerConfigurer 的整合。該方式需要在 Spring 的配置檔案中加入以下內容:

    <!-- Mapper代理開發,使用Spring自動掃描MyBatis的介面並裝配 (Sprinh將指定包中的所有被@Mapper註解標註的介面自動裝配為MyBatis的對映介面) -->
   <!--配置掃描,將MyBatis介面加入IoC容器中提供給外部使用-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- mybatis-spring元件的掃描器,com.dao只需要介面(介面方法與SQL對映檔案中的相同) --> <property name="basePackage" value="com.dao" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> </bean>

如果理解不了上面橙色標記的話的含義,根據上面的程式碼其實可以理解成:採用MapperScannerConfigurer掃描類讓dao包的介面和SQL聯絡起來,從而實現呼叫者通過介面自由使用相關資料庫訪問操作的功能。

2、為什麼要利用Spring來整合MyBatis

通過對Spring的講解可以得知Spring的控制反轉機制降低了呼叫者和被呼叫者之間的耦合性,因此將MyBatis放入Spring容器後開發者只需要進行業務處理,不需要再寫 SqlSession 物件的建立、資料庫事務的處理等煩瑣程式碼,提高了開發效率。

SpringMVC

基礎知識

1、MVC概念:

  1. 模型(Model):用於儲存資料以及處理使用者請求的使用者邏輯
  2. 檢視(View):向控制器提交資料,顯示模型中的資料
  3. 控制器(Controller):根據檢視提出的請求判斷將請求和資料提交給哪個模型處理,將處理後的有關接結果交給哪個檢視顯示更新

2、基於Servlet的MVC模式

  1. 模型:一個或多個JavaBean物件,用於儲存資料和處理業務邏輯
  2. 檢視:一個或多個JSP頁面,向控制器提交資料和為模型提供資料顯示,JSP頁面主要使用HTML標記和JavaBean標記顯示資料
  3. 控制器:一個或多個Servlet物件,根據檢視提交的請求進行控制,將請求轉發給處理業務的JavaBean,並將處理結果放到實體模型JavaBean中,輸出給檢視顯示

3、SpringMVC工作原理

  1. 客戶端請求提交到DispatcherServlet;
  2. 由DispatcherServlet控制器尋找到一個或多個HandlerMapping,找到處理請求Controller;
  3. DispatcherServlet將請求提交到Controller
  4. Controller呼叫業務邏輯處理後返回ModelAndView
  5. DispatcherServlet心找一個或多個檢視解析器,找到ModelAndView指定的檢視
  6. 檢視負責把結果顯示在客戶端

4、SpringMVC介面在工作流程中起的作用

  1. SpringMVC所有請求都經過DispatcherServlet來統一分佈,在DispatcherServlet藉助SpringMVC提供的HandlerMapping定位到具體的Controller。
  2. Controller處理完使用者請求後將返回ModelAndView(包含模型和檢視)物件給DispatcherServlet前端控制器。
  3. ViewResolver介面(檢視解析器)在Web應用中查詢View物件,從而將相應的結果渲染給客戶

從巨集觀角度考慮,DispatcherServlet是整個Web應用的控制器;從微觀角度考慮,Controller是單個Http請求處理過程中的控制器,而ModelAndView是Http請求過程中返回的模型和檢視。

4、在ssm整合專案中SpringMvc相關:

web.xml配置檔案

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    id="WebApp_ID" version="3.1">
    <display-name>StudentShopping</display-name>
    <!-- needed for ContextLoaderListener -->
    <!-- Spring載入ApplicationContext容器 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    <!-- Bootstraps the root web application context before servlet initialization -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

<!-- 部署DispatcherServlet -->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- springmvc配置檔案 -->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <absolute-ordering />
</web-app>

SpringMVC的配置檔案內包含的 Controller對映以及檢視解析器:

<?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"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    <context:component-scan
        base-package="com.controller" />

    <mvc:annotation-driven />
    <mvc:resources location="/css/" mapping="/css/**"></mvc:resources>
    <mvc:resources location="/images/" mapping="/images/**"></mvc:resources>
    <mvc:resources location="/logos/" mapping="/logos/**"></mvc:resources>
    
    <!-- LoginController控制類將對映到“/login”介面,之後都用@RequetMapping代替 -->
    <bean name="/login" class="com.controller.admin.LoginController"/>
  <!-- 檢視解析器,從InternalResourceViewResolver的字尾可以看出這個就是檢視解析器-->
    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver"
        id="internalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>

    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
        p:defaultEncoding="UTF-8" 
        p:maxUploadSize="5400000"
        p:uploadTempDir="fileUpload/temp">
    </bean>

<!--    <bean class="com.exception.MyExceptionHandler"/> -->
</beans>