天天看點

Spring架構IOC詳解

Spring架構學習01

spring架構的概述以及spring中基于XML的IOC配置

1. 什麼是spring?

來自百度:

Spring是一個輕量級的控制反轉(IoC)和面向切面(AOP)的容器架構。

輕量——從大小與開銷兩方面而言Spring都是輕量的。完整的Spring架構可以在一個大小隻有1MB多的JAR檔案裡釋出。并且Spring所需的處理開銷也是微不足道的。此外,Spring是非侵入式的:典型地,Spring應用中的對象不依賴于Spring的特定類。

控制反轉——Spring通過一種稱作控制反轉(IoC)的技術促進了松耦合。當應用了IoC,一個對象依賴的其它對象會通過被動的方式傳遞進來,而不是這個對象自己建立或者查找依賴對象。你可以認為IoC與JNDI相反——不是對象從容器中查找依賴,而是容器在對象初始化時不等對象請求就主動将依賴傳遞給它。

面向切面——Spring提供了面向切面程式設計的豐富支援,允許通過分離應用的業務邏輯與系統級服務(例如審計(auditing)和事務(transaction)管理)進行内聚性的開發。應用對象隻實作它們應該做的——完成業務邏輯——僅此而已。它們并不負責(甚至是意識)其它的系統級關注點,例如日志或事務支援。

2.Spring的優勢

1.友善解耦,簡化開發

2.AOP程式設計支援

3.聲明式事務的支援

4.友善程式的測試

5.友善內建各種優秀架構

6.降低JavaEE API的使用難度

這裡一說可能大家都看不懂優點都是什麼意思,不過沒關系,這些優勢我們會在後來的部落格中一點一點總結深入,今天我們主要詳細了解的就是IOC,是以AOP我們暫時不談,先講一講為什麼需要引入IOC。

Spring架構IOC詳解

上圖講的就是Spring架構的結構體系,今天我們詳細講解的就是 Core Container部分,就是Spring的核心容器,IOC相關的内容,Spring任何的其他部分要運作,必須得有核心容器的支援。

我們先用一個案例來入門,了解一下Spring架構的其中一個核心内容IOC的作用

案例:

正常情況下我們連接配接資料庫進行查詢操作的代碼如下:

package com.jack.jdbc;

import java.sql.*;

/**
 * @Author: Jack
 * @date: 2019/10/21 19:25
 */
public class JdbcDemo01 {
    public static void main(String[] args) throws SQLException {
        //1.注冊驅動
        DriverManager.registerDriver(new com.mysql.jdbc.Driver());
        //2.擷取連接配接
        Connection connection = DriverManager.getConnection("jdbc:mysql:///day23","root","root");
        //3.建立執行sql語句的statement對象
        PreparedStatement preparedStatement = connection.prepareStatement("select * from account");
        //4.執行sql語句,獲得結果集
        ResultSet resultSet = preparedStatement.executeQuery();
        //5.周遊結果集
        while (resultSet.next()){
            System.out.println("   id:"+resultSet.getString(1));
            System.out.println("  uid:"+resultSet.getString(2));
            System.out.println("Money:"+resultSet.getString(3));
        }
        //6.釋放資源
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
}

           

代碼寫完了我們可以從代碼中看出

沒有注冊驅動,就不能獲得連接配接,沒有獲得連接配接就不能建立PreparedStatement ,不能建立PreparedStatement 就不能執行sql語句。。。一環套一環,缺一不可。

是以一個功能的實作都是各種類和方法之間的依賴,這就叫做耦合性,分為類之間依賴和方法間依賴。

解耦:降低程式間的依賴關系

在實際開發中,真正的做到沒有依賴完全獨立不太可能,是以實際開放中的解耦就是要做到

編譯期間不依賴,運作時才依賴

解耦的思路:

第一步:使用反射來建立對象,而不是使用new關鍵字。

//1.注冊驅動
        DriverManager.registerDriver(new com.mysql.jdbc.Driver());
        Class.forName("com.mysql.jdbc.Driver");
           

這樣做的好處就是,我們注冊驅動的時候不再是需要一個具體的類,而是隻要有一段正确的描述類名的字元串就行了。

但是也存在他的問題,我們注冊驅動的時候,使用反射就已經把要注冊的驅動類型寫死,以後在使用其他資料庫的時候,會相當的麻煩。

解決方案:使用讀取配置檔案來擷取 要建立的對象的全限定類名

在我們平時做服務端開發的時候,我們一般都使用的是三層架構,也就是界面層,業務邏輯層,資料通路層三層,一般處理的業務邏輯就是界面層調用業務邏輯層,業務邏輯層調用資料通路層這樣的邏輯,具有很強的耦合性,三層之間缺一不可,我們使用spring架構的核心内容IOC就是解決了這三層之間的耦合性的問題。

IOC控制反轉

inversion of control,把對象建立的權力叫給架構,是架構的重要特征,大幅度降低了耦合。注意不是完全的消除耦合。今天我們主要介紹的就是spring的ioc。

入門案例:

1.導入jar包:

因為我使用的是maven項目,這裡我就把坐标貼一下

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
           
Spring架構IOC詳解

2.建立一個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">
    
</beans>
           

3.把對象的建立交給spring來管理

<bean id="accountService" class="com.jack.service.imp.AccountServiceImpl"/>

<bean id="accountDao" class="com.jack.dao.impl.AccountDaoImpl"/>
           

4.代碼測試一下

//擷取核心容器對象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //根據id擷取bean對象
        AccountService accountService = (AccountService) ac.getBean("accountService");
        AccountDao accountDao = ac.getBean("accountDao",AccountDao.class);

        System.out.println(accountService);
        System.out.println(accountDao);
           
Spring架構IOC詳解

根據運作結果我們可以發現,在操作過程中,我們并沒有使用new關鍵字執行個體化任何一個對象,但是在列印結果中我們可以看到,兩個對象都被執行個體化了,這就是springIOC的基本操作。

配置檔案 -> 解析配置檔案獲得全類名 -> 反射建立對象。

符合我們通過解析配置檔案,擷取要建立對象的全限定類名,通過反射建立對象的降低耦合度的思路

是以IOC的就是一個容器,我們把需要用到的類全部都放在ioc中,在spring中登記,在适當的時候,spring會把你需要的類給你,并且同時也在适當的時候,把你交給其他需要你的類,一個類的生命周期不再決定于引用他的對象,而是全部交spring架構管理,對于對象來講,以前是對象控制其他的對象,但是現在,是spring控制所有的對象,這就叫做控制反轉。

Spring架構IOC詳解

IOC的一些其他細節

—細節1

核心容器的兩個接口:

1.ApplicationContext(單例對象适用)

建構核心容器時,建立對象采取的政策是立即加載的方式,也就是說,一讀取完配置檔案,就立刻建立配置檔案中注冊的對象。

2.BeanFactory(多例對象适用)

在建構核心容器的時,建立對象采取的是延遲加載的政策,什麼時候根據id擷取對象的時候,才真正的建立對象。

但是我們思考一個問題,ApplicationContext在我們配置檔案讀取的時候就把對象建立了,但是如果我們要第二次使用某個對象,肯定要再次的調用建立對象的方法,這樣看來,我們還不如不着急的建立對象,幹脆等到什麼時候用,什麼時候建立對象。是以根據應用場景來看,ApplicationContext和BeanFactory都有使用的必要,不過在實際情況中,spring架構具有強大的功能,非常智能,可以根據我們配置的不同,去改變建立對象的政策,是以兩個接口建立對象的政策顯得不是那麼的重要,但是因為BeanFactory是一個頂級的接口,功能不夠完善,是以在日常的開發中,多數情況下還是選擇使用ApplicationContext接口來定義容器對象。

—細節2

建立Bean對象的方式(三種):

1.使用目标類中的預設構造函數來建立對象:

采用的是目标類中的構造方法來建立對象,如果目标類中沒有預設的構造方法(空參構造方法),則無法建立對象。

2.使用某個類中的方法來建立目标類對象

某個類(工廠類)

public class ServiceFactory {
    public AccountService getAccountService(){
        return new AccountServiceImpl();
    }
}
           

spring配置檔案:

<bean id="factory" class="com.jack.Utils.ServiceFactory"/>
    <bean id="accountService" factory-bean="factory" factory-method="getAccountService"/>
           

首先在配置檔案中注冊工廠類,也就是說執行個體化了工廠類,然後再注冊要執行個體化的目标類(AccountService ),factory-bean指定哪個類中的方法可以建立目标對象,factory-method指定工廠類中的哪個方法來建立對象。

3.使用工廠類中的靜态方法來建立目标對象

工廠類和靜态方法

public class StaticFactory {
    public static AccountService getAccountService(){
        return new AccountServiceImpl();
    }
}
           

spring配置檔案

—細節3

bean的作用範圍

這個就非常簡單了,隻要設定一下scope标簽就好了,我們來挨個說。

1.singleton:顧名思義,就是設定spring建立對象為單例的。

spring配置檔案:

測試類:

//擷取核心容器對象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        AccountService accountService1 = ac.getBean("accountService", AccountService.class);
        AccountService accountService2 = ac.getBean("accountService", AccountService.class);
        System.out.println(accountService1 == accountService2);
           

執行結果如下:

Spring架構IOC詳解

可以看到AccountService的構造函數僅執行了一次,并且兩個AccountService對象的比較列印結果為true

2.prototype:多例的

執行結果如下:

Spring架構IOC詳解

AccountService的構造函數執行了兩次,也就是說,AccountService建立了兩次。

3.request

作用域為 web應用的請求範圍

4.session

作用域為 web應用的會話範圍

5.global-session

作用域為叢集web應用的會話範圍

—細節4

bean對象的生命周期

分為單例對象和多例對象

單例對象的生命周期為:

出生:容器建立時,對象建立

生存:隻要容器存在,對象一直存在

死亡:容器銷毀時,對象死亡

單例對象和容器的生命周期相同,同生共死。

多例對象的生命周期:

出生:使用對象時,spring才為我們建立對象

生存:對象隻要是在使用過程中就一直生存。

死亡:當對象長時間不用,并且沒有别的對象引用的時候,java的垃圾回收機制把對象消亡。

繼續閱讀