08 Spring框架的概念、優點、體系結構、耦合性和IOC(反轉控制)

1.spring介紹java

  Spring 是分層的 Java SE/EE 應用 full-stack 輕量級開源框架,以 IoC(Inverse Of Control: 反轉控制)AOP(Aspect Oriented Programming:面向切面編程)爲內核,提供了展示層 Spring MVC 和持久層 Spring JDBC 以及業務層事務管理等衆多的企業級應用技術,還能整合開源世界衆多著名的第三方框架和類庫,逐漸成爲使用最多的 Java EE 企業應用開源框架。web

2.Spring的優點spring

(1)方便解耦,簡化開發編程

  經過 Spring 提供的 IoC 容器,能夠將對象間的依賴關係交由 Spring 進行控制,避免硬編碼所形成的過分程序耦合。用戶也沒必要再爲單例模式類、屬性文件解析等這些很底層的需求編寫代碼,可 以更專一於上層的應用。設計模式

(2)AOP 編程的支持tomcat

  經過 Spring 的 AOP 功能,方便進行面向切面的編程,許多不容易用傳統 OOP 實現的功能能夠經過 AOP 輕鬆應付。session

(3)聲明式事務的支持數據結構

  能夠將咱們從單調煩悶的事務管理代碼中解脫出來,經過聲明式方式靈活的進行事務的管理, 提升開發效率和質量。框架

(4)方便程序的測試maven

  能夠用非容器依賴的編程方式進行幾乎全部的測試工做,測試再也不是昂貴的操做,而是隨手可作的事情。

(5)方便集成各類優秀框架

  Spring 能夠下降各類框架的使用難度,提供了對各類優秀框架(Struts、Hibernate、Hessian、Quartz 等)的直接支持。

(6)下降 JavaEE API 的使用難度

Spring 對 JavaEE API(如 JDBC、JavaMail、遠程調用等)進行了薄薄的封裝層,使這些 API 的使用難度大爲下降。

(7)Java 源碼是經典學習範例

Spring 的源代碼設計精妙、結構清晰、匠心獨用,到處體現着大師對 Java 設計模式靈活運用以及對 Java 技術的高深造詣。它的源代碼無心是 Java 技術的最佳實踐的範例。

3.Spring的體系結構

4.耦合性介紹

  耦合性(Coupling),也叫耦合度,是對模塊間關聯程度的度量。耦合的強弱取決於模塊間接口的複雜性、調用模塊的方式以及經過界面傳送數據的多少。模塊間的耦合度是指模塊之間的依賴關係,包括控制關係、調用關係、數據傳遞關係。模塊間聯繫越多,其耦合性越強,同時代表其獨立性越差( 下降耦合性,能夠提升其獨立性)。耦合性存在於各個領域,而非軟件設計中獨有的,可是咱們只討論軟件工程中的耦合。

  在軟件工程中,耦合指的就是就是對象之間的依賴性。對象之間的耦合越高,維護成本越高。所以對象的設計應使類和構件之間的耦合最小。軟件設計中一般用耦合度和內聚度做爲衡量模塊獨立程度的標準。劃分模塊的一個準則就是高內聚低耦合

  耦合性有以下分類:

  (1)內容耦合。當一個模塊直接修改或操做另外一個模塊的數據時,或一個模塊不經過正常入口而轉入另外一個模塊時,這樣的耦合被稱爲內容耦合。內容耦合是最高程度的耦合,應該避免使用之。

  (2)公共耦合。兩個或兩個以上的模塊共同引用一個全局數據項,這種耦合被稱爲公共耦合。在具備大量公共耦合的結構中,肯定到底是哪一個模塊給全局變量賦了一個特定的值是十分困難的。

  (3)  外部耦合 。一組模塊都訪問同一全局簡單變量而不是同一全局數據結構,並且不是經過參數表傳遞該全局變量的信息,則稱之爲外部耦合。

  (4)  控制耦合 。一個模塊經過接口向另外一個模塊傳遞一個控制信號,接受信號的模塊根據信號值而進行適當的動做,這種耦合被稱爲控制耦合。

  (5)標記耦合 。若一個模塊 A 經過接口向兩個模塊 B 和 C 傳遞一個公共參數,那麼稱模塊 B 和 C 之間存在一個標記耦合。

  (6)  數據耦合。模塊之間經過參數來傳遞數據,那麼被稱爲數據耦合。數據耦合是最低的一種耦合形式,系統中通常都存在這種類型的耦合,由於爲了完成一些有意義的功能,每每須要將某些模塊的輸出數據做爲另外一些模塊的輸入數據。

  (7)  非直接耦合 。兩個模塊之間沒有直接關係,它們之間的聯繫徹底是經過主模塊的控制和調用來實現的。

  總之,耦合是影響軟件複雜程度和設計質量的一個重要因素,在設計上咱們應採用如下原則:若是模塊間必須存在耦合,就儘可能使用數據耦合,少用控制耦合,限制公共耦合的範圍,儘可能避免使用內容耦合。

4.程序的耦合
耦合:程序間的依賴關係
  包括:
    類之間的依賴
    方法間的依賴
解耦:下降程序間的依賴關係
實際開發中:應該作到:編譯期不依賴,運行時才依賴。
解耦的思路
  第一步:使用反射來建立對象,而避免使用new關鍵字。
  第二步:經過讀取配置文件來獲取要建立的對象全限定類名

5.IOC原理

Inverse Of Control: 反轉控制

原來:咱們在獲取對象時,都是採用 new 的方式。是主動的。

如今:咱們獲取對象時,同時跟工廠要,有工廠爲咱們查找或者建立對象。是被動的。

這種被動接收的方式獲取對象的思想就是控制反轉,它是 spring 框架的核心之一。

明確 ioc 的做用:削減計算機程序的耦合(解除咱們代碼中的依賴關係)。

5.spring基於XML的IOC環境搭建和入門

spring5 版本是用 jdk8編寫的,因此要求咱們的 jdk 版本是 8 及以上。同時 tomcat 的版本要求 8.5及以上。

(1)建立一個maven的純java工程,在pom文件中,添加spring依賴

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
    </dependencies>

(2)建立業務層接口和實現類

<1>業務層接口

package service;

/**
 * 帳戶業務層的接口
 */
public interface IAccountService {

    /**
     * 模擬保存帳戶
     */
    void saveAccount();
}

<2>實現類

package service.impl;
import dao.IAccountDao;
import dao.impl.AccountDaoImpl;
import service.IAccountService;

/**
 * 帳戶的業務層實現類
 */
public class AccountServiceImpl implements IAccountService {

    private IAccountDao accountDao = new AccountDaoImpl();

    public void  saveAccount(){
        accountDao.saveAccount();
    }
}

(3)建立持久層接口和實現類

<1>持久層接口

package dao;

/**
 * 帳戶的持久層接口
 */
public interface IAccountDao {

    /**
     * 模擬保存帳戶
     */
    void saveAccount();
}

<2>實現類

package dao.impl;

import dao.IAccountDao;

/**
 * 帳戶的持久層實現類
 */
public class AccountDaoImpl implements IAccountDao {

    public  void saveAccount(){

        System.out.println("保存了帳戶");
    }
}

(4)建立bean.xml,讓 spring 管理資源,在配置文件中配置 service 和 dao

<!--把對象的建立交給spring來管理-->
spring對bean的管理細節
  1.建立bean的三種方式
  2.bean對象的做用範圍
  3.bean對象的生命週期

(1)建立Bean的兩種方式
  第一種方式:使用默認構造函數建立。
    在spring的配置文件中使用bean標籤,配以id和class屬性以後,且沒有其餘屬性和標籤時。
    採用的就是默認構造函數建立bean對象,此時若是類中沒有默認構造函數,則對象沒法建立。注意:這裏說的沒有默認構造函數,是指構造函數被修改,而默認的構造函數又沒有。

下面的代碼是沒有默認的構造函數的:

package service.impl;
import dao.IAccountDao;
import dao.impl.AccountDaoImpl;
import service.IAccountService;

/**
 * 帳戶的業務層實現類
 */
public class AccountServiceImpl implements IAccountService {//帶參數的構造函數
    public AccountServiceImpl(String name) {
    }

    public void  saveAccount(){
        //accountDao.saveAccount();
        System.out.println("AccountServiceImpl中的saveAccount方法執行了");
    }

}

下面的代碼是有構造函數的。

package service.impl;
import dao.IAccountDao;
import dao.impl.AccountDaoImpl;
import service.IAccountService;

/**
 * 帳戶的業務層實現類
 */
public class AccountServiceImpl implements IAccountService {
//默認的構造函數
    public AccountServiceImpl() {
    }

    //帶參數的構造函數
    public AccountServiceImpl(String name) {
    }

    public void  saveAccount(){
        //accountDao.saveAccount();
        System.out.println("AccountServiceImpl中的saveAccount方法執行了");
    }

}

注意:如下的代碼是有默認的構造方法的

package service.impl;
import dao.IAccountDao;
import dao.impl.AccountDaoImpl;
import service.IAccountService;

/**
 * 帳戶的業務層實現類
 */
public class AccountServiceImpl implements IAccountService {


    public void  saveAccount(){
        //accountDao.saveAccount();
        System.out.println("AccountServiceImpl中的saveAccount方法執行了");
    }

}

使用默認構造函數建立的配置方式:

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

  第二種方式: 使用普通工廠中的方法建立對象(使用某個類中的方法建立對象,並存入spring容器)

InstanceFactory.java這個類模擬一個工廠類,建立jar包找那個的某個類的對象。

package factory;
import service.IAccountService;
import service.impl.AccountServiceImpl;

/**
 * 模擬一個工廠類(該類多是存在於jar包中的,咱們沒法經過修改源碼的方式來提供默認構造函數)
 */
public class InstanceFactory {

    public IAccountService getAccountService(){
        return new AccountServiceImpl();
    }
}

 使用普通工廠中的方法建立對象的配置方法:

<!--第二種方式: 使用普通工廠中的方法建立對象(使用某個類中的方法建立對象,並存入spring容器)-->
   <bean id="instanceFactory" class="factory.InstanceFactory"></bean>
   <bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>

(2)bean的做用範圍調整
bean標籤的scope屬性:
  做用:用於指定bean的做用範圍
  取值: 經常使用的就是單例的和多例的
    singleton:單例的(默認值)
    prototype:多例的
    request:做用於web應用的請求範圍
    session:做用於web應用的會話範圍
    global-session:做用於集羣環境的會話範圍(全局會話範圍),當不是集羣環境時,它就是session

<bean id="accountService" class="service.impl.AccountServiceImpl" scope="prototype"></bean>

測試效果:

package ui;
import dao.IAccountDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.IAccountService;
import service.impl.AccountServiceImpl;

/**
 * 模擬一個表現層,用於調用業務層
 */
public class Client {

    /**
     * 獲取spring的Ioc核心容器,並根據id獲取對象
     *
     * ApplicationContext的三個經常使用實現類:
     *      ClassPathXmlApplicationContext:它能夠加載類路徑下的配置文件,要求配置文件必須在類路徑下。不在的話,加載不了。(更經常使用)
     *      FileSystemXmlApplicationContext:它能夠加載磁盤任意路徑下的配置文件(必須有訪問權限)
     *
     *      AnnotationConfigApplicationContext:它是用於讀取註解建立容器的,是明天的內容。
     *
     * 核心容器的兩個接口引起出的問題:
     *  ApplicationContext:     單例對象適用              採用此接口
     *      它在構建核心容器時,建立對象採起的策略是採用當即加載的方式。也就是說,只要一讀取完配置文件立刻就建立配置文件中配置的對象。
     *
     *  BeanFactory:            多例對象使用
     *      它在構建核心容器時,建立對象採起的策略是採用延遲加載的方式。也就是說,何時根據id獲取對象了,何時才真正的建立對象。
     * @param args
     */
    public static void main(String[] args) {
        //1.獲取核心容器對象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");

        //2.根據id獲取Bean對象,注意id是在bean.xml文件配置的
        IAccountService as1  = (IAccountService)ac.getBean("accountService");
        IAccountService as2  = (IAccountService)ac.getBean("accountService");
        System.out.println(as1==as2);
        
    }
}

控制檯輸出:

(3)bean對象的生命週期
單例對象
  出生:當容器建立時對象出生
  活着:只要容器還在,對象一直活着
  死亡:容器銷燬,對象消亡
總結:單例對象的生命週期和容器相同
多例對象
  出生:當咱們使用對象時spring框架爲咱們建立
  活着:對象只要是在使用過程當中就一直活着。
  死亡:當對象長時間不用,且沒有別的對象引用時,由Java的垃圾回收器回收

<?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
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--把對象的建立交給sping來管理-->
    <bean id="accountService" class="service.impl.AccountServiceImpl"></bean>
    <bean id="accountDao" class="dao.impl.AccountDaoImpl"></bean>

</beans>

(5)表現層

package ui;
import dao.IAccountDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.IAccountService;
import service.impl.AccountServiceImpl;

/**
 * 模擬一個表現層,用於調用業務層
 */
public class Client {

    /**
     * 獲取spring的Ioc核心容器,並根據id獲取對象
     *
     * ApplicationContext的三個經常使用實現類:
     *      ClassPathXmlApplicationContext:它能夠加載類路徑下的配置文件,要求配置文件必須在類路徑下。不在的話,加載不了。(更經常使用)
     *      FileSystemXmlApplicationContext:它能夠加載磁盤任意路徑下的配置文件(必須有訪問權限)
     *
     *      AnnotationConfigApplicationContext:它是用於讀取註解建立容器的,是明天的內容。
     *
     * 核心容器的兩個接口引起出的問題:
     *  ApplicationContext:     單例對象適用              採用此接口
     *      它在構建核心容器時,建立對象採起的策略是採用當即加載的方式。也就是說,只要一讀取完配置文件立刻就建立配置文件中配置的對象。
     *
     *  BeanFactory:            多例對象使用
     *      它在構建核心容器時,建立對象採起的策略是採用延遲加載的方式。也就是說,何時根據id獲取對象了,何時才真正的建立對象。
     * @param args
     */
    public static void main(String[] args) {
        //1.獲取核心容器對象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//        ApplicationContext ac = new FileSystemXmlApplicationContext("C:\\Users\\zhy\\Desktop\\bean.xml");
        //2.根據id獲取Bean對象,注意id是在bean.xml文件配置的
        IAccountService as  = (IAccountService)ac.getBean("accountService");
        IAccountDao adao = ac.getBean("accountDao", IAccountDao.class);

        System.out.println(as);
        System.out.println(adao);
        as.saveAccount();
    }
}

控制檯輸出:

相關文章
相關標籤/搜索