Spring IOC 概念及作用


一:程序之間的耦合及解決

    耦合性(Coupling):也叫耦合度,是對模塊間關聯程度的度量。耦合的強弱取決於模塊間接口的復雜性、調用模塊的方式以及通過界面傳送數據的多少。模塊間的耦合度是指模塊之間的依賴關系,包括控制關系、調用關系、數據傳遞關系。模塊間聯系越多,其耦合性越強,同時表明其獨立性越差( 降低耦合性,可以提高其獨立性)。耦合性存在於各個領域,而非軟件設計中獨有的。
  在軟件工程中,耦合指的就是就是對象之間的依賴性。對象之間的耦合越高,維護成本越高。因此對象的設計應使類和構件之間的耦合最小。軟件設計中通常用耦合度和內聚度作為衡量模塊獨立程度的標准。划分模塊的一個准則就是高內聚低耦合。

1:耦合的分類

①:內容耦合:
   當一個模塊直接修改或操作另一個模塊的數據時,或一個模塊不通過正常入口而轉入另一個模塊時,這樣的耦合被稱為內容耦合。內容耦合是最高程度的耦合,應該避免使用之。
②:公共耦合:
   兩個或兩個以上的模塊共同引用一個全局數據項,這種耦合被稱為公共耦合。在具有大量公共耦合的結構中,確定究竟是哪個模塊給全局變量賦了一個特定的值是十分困難的。
③: 外部耦合 :
   一組模塊都訪問同一全局簡單變量而不是同一全局數據結構,而且不是通過參數表傳遞該全局變量的信息,則稱之為外部耦合。
④: 控制耦合 :
   一個模塊通過接口向另一個模塊傳遞一個控制信號,接受信號的模塊根據信號值而進行適當的動作,這種耦合被稱為控制耦合。
⑤:標記耦合 :
   若一個模塊 A 通過接口向兩個模塊 B 和 C 傳遞一個公共參數,那么稱模塊 B 和 C 之間存在一個標記耦合。
⑥: 數據耦合:
   模塊之間通過參數來傳遞數據,那么被稱為數據耦合。數據耦合是最低的一種耦合形式,系統中一般都存在這種類型的耦合,因為為了完成一些有意義的功能,往往需要將某些模塊的輸出數據作為另一些模塊的輸入數據。
⑦: 非直接耦合 :
   兩個模塊之間沒有直接關系,它們之間的聯系完全是通過主模塊的控制和調用來實現的。

2:耦合總結

  耦合是影響軟件復雜程度和設計質量的一個重要因素,在設計上我們應采用以下原則:如果模塊間必須存在耦合,就盡量使用數據耦合,少用控制耦合,限制公共耦合的范圍,盡量避免使用內容耦合。

3:擴展(內聚和耦合的使用)

  內聚標志一個模塊內各個元素彼此結合的緊密程度,它是信息隱蔽和局部化概念的自然擴展。內聚是從功能角度來度量模塊內的聯系,一個好的內聚模塊應當恰好做一件事。它描述的是模塊內的功能聯系。耦合是軟件結構中各模塊之間相互連接的一種度量,耦合強弱取決於模塊間接口的復雜程度、進入或訪問一個模塊的點以及通過接口的數據。 程序講究的是低耦合,高內聚。就是同一個模塊內的各個元素之間要高度緊密,但是各個模塊之間的相互依存度卻要不那么緊密。內聚和耦合是密切相關的,同其他模塊存在高耦合的模塊意味着低內聚,而高內聚的模塊意味着該模塊同其他模塊之間是低耦合。在進行軟件設計時,應力爭做到高內聚,低耦合。

4:呈現耦合的代碼片段

##### 第一種常見的耦合狀態
/**
 * 學生業務處理實現類
 * @author ant
 */
public class StudentServiceImpl implements StudentService {

    //組合了持久層對象
    private StudentDao studentDao = new StudentDaoImpl();

    /**
     * @method 模擬保存學生方法實現
     */
    public void save() {
        //調用dao的保存數據方法
        studentDao.save();
    }
}
// 業務層調用持久層,並且此時業務層在依賴持久層的接口和實現類。
// 如果此時沒有持久層實現類,編譯將不能通過。這種編譯期依賴關系,
// 應該在我們開發中杜絕。我們需要優化代碼解決。


##### 第二種耦合
// 問題:在JDBC注冊驅動時我們為什么不使用 DriverManager 的 registerDriver 方法,而是采用 Class.forName("xxx") 的方式?

//1.注冊驅動
//DriverManager.registerDriver(new com.mysql.jdbc.Driver()); 為什么不使用這個
        Class.forName("com.mysql.jdbc.Driver");
//2.獲取連接
//3.獲取預處理 sql 語句對象
//4.獲取結果集
//5.遍歷結果集

// 回答:其實我們的類依賴了數據庫的具體驅動類(MySQL),
// 如果使用registerDriver方法注冊,會存在一定的耦合,依賴具體的驅動類,如果不存在com.mysql.jdbc.Driver類,則運行都不行,
// 而Class.forName則解決了這種問題,因為它是接收字符串,不在依賴具體驅動類,同時,也產生了一個新的問題,mysql 驅動的全限定類名字符串是在 java 類中寫死的,一旦要改還是要修改源碼。解決這個問題也很簡單,使用配置文件配置。不使用工廠模式展示代碼耦合
程序耦合的2個小實例

5:使用工廠模式解耦

  在實際開發中我們可以把三層的對象都使用配置文件配置起來,當啟動服務器應用加載的時候,讓一個類中的方法通過讀取配置文件,把這些對象創建出來並存起來。在接下來的使用的時候,直接拿過來用就好了。那么,這個讀取配置文件,創建和獲取三層對象的類就是工廠

工廠創建的對象存在哪呢?:

  那肯定要要找個集合來存。這時候有 Map 和 List 供選擇。到底選 Map 還是 List 就看我們有沒有查找需求。有查找需求,選 Map。所以我們的答案就是在應用加載時,創建一個 Map,用於存放三層對象。我們把這個 map 稱之為容器。

什么是工廠呢?:

  工廠就是負責給我們從容器中獲取指定對象的類。這時候我們獲取對象的方式發生了改變。

 ①:不使用工廠模式之前的耦合代碼

#####StudentDao接口

public interface StudentDao {
    /**
     * @method 模擬保存學生接口方法
     */
    void save();
}

+++++++++++++++++++++++++++++++++++++++++
        #####StudentDao接口實現類

public class StudentDaoImpl implements StudentDao {
    /**
     * @method 模擬保存學生方法實現
     */
    public void save() {
        System.out.println("==》保存完成《==");
    }
}

+++++++++++++++++++++++++++++++++++++++++
        ##### StudentService業務接口

public interface StudentService {
    /**
     * @method 模擬保存學生接口方法
     */
    void save();
}

+++++++++++++++++++++++++++++++++++++++++
        ##### StudentServiceImpl 業務接口實現類

/**
 * 學生業務處理實現類
 * @author ant
 */
public class StudentServiceImpl implements StudentService {
    //組合
    private StudentDao studentDao = new StudentDaoImpl();

    /**
     * @method 模擬保存學生方法實現
     */
    public void save() {
        //調用dao的保存數據方法
        studentDao.save();
    }
}

+++++++++++++++++++++++++++++++++++++++++
        ##### 測試類

public class Client {
    public static void main(String[] args) throws SQLException {
        //創建StudentService對象實體后調用操作
        StudentService studentService=new StudentServiceImpl();
        studentService.save();
    }
}

//這個就是我們平常寫的三層架構,成功的展示了代碼的耦合,這時候隨便刪除一個類代碼都會報代碼錯誤
不使用工廠模式展示代碼耦合

 ②:使用工廠模式進行解耦

##### 第一種工廠對象  產生的是多例對象 
/**
 * 第一種它是多例,這個工廠效率低,因為每次調用都要重新匹配,
 * 然后獲取和實例化返回,來回創建對象,會對程序的性能有所影響
 */
public class BeanFactory {
    //聚合Properties配置類
    private static Properties prop;
    //初始化Properties數據
    static {
        prop = new Properties();
        try {
            //獲取文件加載到Properties對象里
            prop.load(BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"));
        } catch (Exception e) {
            throw new RuntimeException("讀取配置失敗");
        }
    }
    //根據鍵獲取相應對象
    public static Object getBean(String name) {
        //根據鍵獲取value
        String property = prop.getProperty(name);
        Object obj = null;
        try {
            //通過反射獲取對象實例 每次都重新實例化
            obj = Class.forName(property).getConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("無法注冊");
        }
        //返回對象
        return obj;
    }
}

+++++++++++++++++++++++++++++++++++++++++
##### 第二種工廠對象  產生的是單例對象 
/**
 * 這種是簡單的單例工廠,把數據全部存放於容器中,然后要的時候獲取,
 */
public class BeanFactory {
    //聚合Properties配置類
    private final static Properties prop;
    //創建容器存儲對象
    private final static Map<String, Object> beans;

    //初始化
    static {
        //為2個對象賦值
        prop = new Properties();
        beans = new HashMap<String, Object>();
        try {
            //獲取文件加載到Properties對象里
            prop.load(BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"));
            //獲取配置文件全部key
            Enumeration<Object> keys = prop.keys();
            //循環獲取值 然后實例化存儲到map容器
            while (keys.hasMoreElements()) {
                String key = keys.nextElement().toString();
                String value = prop.getProperty(key);
                Object bean = Class.forName(value).getConstructor().newInstance();
                beans.put(key, bean);

            }
        } catch (Exception e) {
            throw new RuntimeException("讀取配置失敗");
        }
    }

    //根據鍵獲取相應對象
    public static Object getBean(String name) {
        //從容器獲取返回
        if (beans.containsKey(name)) {
            return beans.get(name);
        }
        return null;
    }
}
工廠的2種寫的方式
##### StudentDao持久層接口
public interface StudentDao {
    /**
     * @method 模擬保存學生接口方法
     */
    void save();
}

+++++++++++++++++++++++++++++++++++++++++
##### StudentDaoImpl持久層接口實現類
public class StudentDaoImpl implements StudentDao {
    /**
     * @method 模擬保存學生方法實現
     */
    public void save() {
        System.out.println("==》保存完成《==");
    }
}

+++++++++++++++++++++++++++++++++++++++++
##### StudentService業務層接口
public interface StudentService {
    /**
     * @method 模擬保存學生接口方法
     */
    void save();
}

+++++++++++++++++++++++++++++++++++++++++
##### StudentServiceImpl業務接口實現類
public class StudentServiceImpl implements StudentService {
    //聚合StudentDao接口
    private static StudentDao studentDao;
    //初始化
    static{
        studentDao = (StudentDaoImpl)BeanFactory.getBean("studentDao");
    }
    /**
     * @method 模擬保存學生方法實現
     */
    public void save() {
        //調用dao的保存數據方法
        studentDao.save();
    }
}

+++++++++++++++++++++++++++++++++++++++++
##### 測試類
public class Client {
    public static void main(String[] args) throws SQLException {
        //創建StudentService對象實體后調用操作
        StudentService studentService=(StudentServiceImpl) BeanFactory.getBean("studentService");
        studentService.save();
    }
}
基本代碼及測試
studentDao=cn.xw.dao.impl.StudentDaoImpl
studentService=cn.xw.service.impl.StudentServiceImpl
bean.properties配置文件

小總結:其實我們在日常開發中,都是不用手動寫控制反轉(解耦)都是由Spring幫我們完成了,因為Spring核心就包括IOC

二:Spring IOC解決程序耦合

1:相應資料

  Spring官網     

  注意:我們現在開發用的Spring版本都是5版本以上的,用jdk8編寫的,同時tomcat版本也要在8.5以上

<!--編寫Spring必須要導入相應坐標-->
<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
    </dependencies>

2:使用Spring實現IOC解決耦合

 ①:編寫Service和Dao接口及實現類

##### StudentDao持久層接口
public interface StudentDao {
    /**
     * @method 模擬保存學生接口方法
     */
    void save();
}

+++++++++++++++++++++++++++++++++++++++++
##### StudentDaoImpl持久層接口實現類
public class StudentDaoImpl implements StudentDao {
    /**
     * @method 模擬保存學生方法實現
     */
    public void save() {
        System.out.println("==》保存完成《==");
    }
}

+++++++++++++++++++++++++++++++++++++++++
##### StudentService業務層接口
public interface StudentService {
    /**
     * @method 模擬保存學生接口方法
     */
    void save();
}

+++++++++++++++++++++++++++++++++++++++++
##### StudentServiceImpl業務接口實現類
public class StudentServiceImpl implements StudentService {
    //聚合StudentDao接口
    private static StudentDao studentDao;
    /**
     * @method 模擬保存學生方法實現
     */
    public void save() {
        ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
        studentDao = app.getBean("studentDao", StudentDao.class);

        //調用dao的保存數據方法
        StudentServiceImpl.studentDao.save();
    }
}
Dao和Service

②:編寫Spring配置文件

<?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">
    <!--把StudentServiceImpl創建放入IOC容器-->
    <bean id="studentService" class="cn.xw.service.impl.StudentServiceImpl"></bean>
    <!--把StudentDaoImpl創建放入IOC容器-->
    <bean id="studentDao" class="cn.xw.dao.impl.StudentDaoImpl"></bean>
</beans>
編寫applicationContext.xml

 ③:測試類

public class Client {
    public static void main(String[] args) throws SQLException {
        ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
        StudentService studentService = app.getBean("studentService", StudentService.class);
        studentService.save();
    }
}
測試類代碼

進行測試后發現是可以運行的,但是問題來啦,這寫的是啥玩意,也看不懂呀,這可咋整,所以這前面代碼只是Spring的簡單入門,在接下來我就會為大家詳細介紹Spring IOC

3:導包的不同方式

 1 手動導入Spring的jar包
 2     spring-aop-5.0.2.RELEASE.jar
 3     spring-beans-5.0.2.RELEASE.jar
 4     spring-context-5.0.2.RELEASE.jar
 5     spring-core-5.0.2.RELEASE.jar
 6     spring-expression-5.0.2.RELEASE.jar
 7     commons-logging-1.2.jar
 8 
 9 
10 
11 在Maven下 我們只需要導入坐標即可
12     <dependency>
13         <groupId>org.springframework</groupId>
14         <artifactId>spring-context</artifactId>
15         <version>5.2.6.RELEASE</version>
16     </dependency>
17 但是我們看看maven給我們導入的jar包
18 Maven: org.springframework:spring-aop:5.2.6.RELEASE
19 Maven: org.springframework:spring-beans:5.2.6.RELEASE
20 Maven: org.springframework:spring-context:5.2.6.RELEASE
21 Maven: org.springframework:spring-core:5.2.6.RELEASE
22 Maven: org.springframework:spring-expression:5.2.6.RELEASE
23 Maven: org.springframework:spring-jcl:5.2.6.RELEASE
24 
25 問題來啦,大家會看見我們手動導入的logging和maven導入的jcl其實是一樣的
26 因為maven把logging日志jar包封裝到了jcl中
導包方式

三:Spring之IOC詳細介紹(基於XML)

1:Spring中IOC實現的工廠類圖結構

2:BeanFactory和ApplicationContext的區別

 在上面一個入門的例子中,大家看我都是使用ApplicationContext及它的實現類來加載配置文件和創建容器的,可是它們的區別是什么?我們仔細看BeanFactory是最頂層的接口,而ApplicationContext是它的子接口,唯一的區別是:

ApplicationContext:它在構造核心容器時,創建對象采取的策略是采用立即加載的方式,也就是說,只要一讀取完配置文件后就會馬上創建配置文件中的對象,然后放入容器中。就像我之前寫的第二種工廠方式,把讀取的配置文件獲取的對象放入Map中。

BeanFactory:它在創建核心容器時,創建對象采取的策略是延遲加載的的方式,也就是說,什么是根據id獲取對象的時候才去創建,然后放入容器中

3:ApplicationContext接口的實現類

①:ClassPathXmlApplicationContext

  它可以加載類路徑下的任何資源,不在就無法加載,src下的都是類路徑,如果在src下是多文件(如在src下的file里面的applicationContext.xml),路徑就要寫file/applicationContext.xml

②:FileSystemXmlApplicationContext

  加載磁盤下任意文件,必須要有訪問權限

③:AnnotationConfigApplicationContext

  用於讀取注解,在注解開發會詳細說

//加載類路徑下的資源
ApplicationContext appA=new ClassPathXmlApplicationContext("applicationContext.xml");
//加載任意文件下的資源
ApplicationContext appB=new FileSystemXmlApplicationContext("D:\\bky_Spring001\\src\\main\\resources\\applicationContext.xml");

4:獲取容器對象

//3種獲取容器對象的方法
//第一種:參數1 容器id屬性 參數2 映射的class對象 此方式是對第三種方式的擴展,防止一個接口有多個實現類
StudentService studentServiceA = app.getBean("studentService", StudentService.class);
//第二種: 參數1 容器id屬性
StudentService studentServiceB = (StudentServiceImpl)app.getBean("studentService");
//第三種: 參數1 要獲取容器對象的class 常用推薦
StudentService studentServiceC = app.getBean(StudentService.class);

5:Spring配置文件bean的三種創建方式

<!--以下面的這個對象為例    下面的3種只能有一種存在-->
    <!--第一種 使用默認構造函數創建,前提必須要有無參構造函數,如果沒有無參構造函數無法創建-->
    <bean id="studentDao" class="cn.xw.dao.impl.StudentDaoImpl"></bean>
    
    <!--第二種創建方式 使用工廠方法創建對象-->
    <!--factory-bean:引用工廠對象路徑 -->
    <!--factory-method:調用工廠中的方法 返回一個對象容器-->
    <bean id="beanFactory" class="cn.xw.utils.BeanFactory"></bean>
    <bean id="studentDao" factory-bean="beanFactory" factory-method="getStudentService"></bean>

    <!--第三種 使用工廠的靜態方法創建對象放到容器中  前提方法必須是靜態的-->
    <bean id="studentDao" class="cn.xw.utils.BeanFactory" factory-method="getstaticStudentService"></bean>
//工廠對象
public class BeanFactory {
    //普通方法
    public StudentDao getStudentService(){
        return new StudentDaoImpl();
    }
    //靜態方法
    public static StudentDao getstaticStudentService(){
        return new StudentDaoImpl();
    }
}

6:Spring中bean的作用范圍(單例或多例)

其實Spring是一個很好的框架,在使用工廠IOC的時候可以指定是單例還是多例

bean標簽參數:scope=“xx” 作用范圍
一:在普通的javaSE工程中可設置
    ①:singleton:           單例對象  默認
    ②:prototype:           多例對象
二:在WEB工程中可設置
    ①:request:                   作用域web的請求范圍,將創建的對象存入request域中   單例
    ②:session:                  作用域web的會話范圍,將創建的對象存入session域中   單例
    ③:globalSession:          作用域web集群會話(不常用)
<!--把StudentDaoImpl創建放入到IOC容器  並設置了單例對象 默認就是單例-->
    <bean id="studentDao" class="cn.xw.dao.impl.StudentDaoImpl" scope="singleton"></bean>

7:Spring中bean生命周期

singleton:單例對象生命周期      prototype:多例對象生命周期
出生:容器創建時對象創建          出生:使用Spring創建,獲取時再創建
活着:容器存在,對象一直存在        活着:對象在使用中一直存在
死亡:IOC容器對象銷毀,對象也就消亡     死亡:長時間不用會被JVM垃圾回收器回收
總結:和IOC容器的生命周期一樣           總結:和我們平時創建對象一樣,長時間不用被JVM回收

 ①:單例模式代碼演示

<!-更改配置文件-->
<!--把StudentServiceImpl創建放入IOC容器-->
<bean id="studentService" class="cn.xw.service.impl.StudentServiceImpl" scope="singleton" init-method="init" destroy-method="destroy"></bean>
public class StudentServiceImpl implements StudentService {
    //聚合StudentDao接口
    private static StudentDao studentDao=new StudentDaoImpl();
    /**
     * @method 模擬保存學生方法實現
     */
    public void save() {
        //調用dao的保存數據方法
        StudentServiceImpl.studentDao.save();
    }
    //加載方法
    public void init(){
        System.out.println("對象被   加載了");
    }
    //銷毀方法
    public void destroy(){
        System.out.println("對象被   銷毀了");
    }
}
 //因為ApplicationContext沒有關閉方法,而子類重寫了父類方法,還增加了關閉方法,所以改用子類
        ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
        //獲取對象  這個是會初始化類 執行init方法
        StudentService studentServiceA = app.getBean("studentService", StudentService.class);
        //調用主體方法
        studentServiceA.save();
        //關閉
        app.close();

注:單例模式下對象是可以進行關閉的,但是ApplicationContext沒有關閉方法,所以要去子類尋找 ,還有 注意一下,Spring5.0.2是可以打印日志的,但是Spring再高版本需要手動設置才可以打印

注:singleton類依賴了prototype類,容器會在singleton類初始化就會根據依賴關系將prototype類注入。以后的每一次調用singleton bean都是同一個對象,里面的prototype bean也是最初注入的那個,容器再也不會為singleton bean產生新的prototype bean

②:多例模式代碼演示

<!--把StudentServiceImpl創建放入IOC容器-->
    <bean id="studentService" class="cn.xw.service.impl.StudentServiceImpl" scope="prototype" init-method="init" destroy-method="destroy"></bean>

 其它代碼和上面一樣,那么為什么關閉方法沒有執行?因為創建的對象為普通對象,Spring不知道你什么時候關閉,所以對象交給JVM垃圾回收器管理

③:Request作用域

    對於每次HTTP請求,使用request定義的Bean都將產生一個新實例,每個HTTP request中的實例都是獨立互不影響的的。針對每次HTTP請求,Spring容器會創建一個全新的cn.xw.xxxx bean的實例,且xxxx bean僅在當前HTTP request內有效。當requestA請求創建並更改了xxxx bean的內部狀態,requestB請求中創建的xxxx bean,並不會有相應的這些狀態變化。 當處理請求結束,request作用域的bean實例將被銷毀。
④:Session作用域
 和Request很類似,對於每個HTTP Session,使用session定義的Bean都將產生一個新實例。每個HTTP Session中的實例都是獨立互不影響的的。 當HTTP Session最終被廢棄的時候,在該HTTP Session作用域內的bean也會被廢棄掉。
 這里重點要明白reques作用域和session作用域的差別:一個http session中可以有多個request;簡單說就是,用戶A訪問同一網站的PageA和PageB,這就有兩個http request,但是只有一個http session;用戶A,B,C三人同時訪問這個網站的PageA,這就有三個http request,同時也有三個 http session

8:Spring依賴注入(重要)

 大家在前面有沒有發現,我們把對象交給Spring管理的時候,我們之前用的是無參構造方法,可是有個疑問,我要創建帶參構造函數怎么辦?

public class StudentServiceImpl implements StudentService {
    //聚合StudentDao接口
    private static StudentDao studentDao;
    /**
     * @method 模擬保存學生方法實現
     */
    public void save() {
        ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml"); studentDao = app.getBean("studentDao", StudentDao.class); //調用dao的保存數據方法
        StudentServiceImpl.studentDao.save();
    }
}

這上面標紅的在這里面使用重新加載讀取配置文件,重新返回容器里某個對象,是否合適呢?其實是很不合適的,但是Spring已經為我們想到了這些問題,使用依賴注入的方法

依賴注入(Dependency Injection):

  它是Spring框架核心IOC的具體表現,在編程的時候我們通過控制反轉交給Spring容器管理對象,但是不能完全實現依賴解耦,這個時候就需要使用到依賴注入了(就是在當前類使用到其他類,這個時候由Spring為當前類提供其它類對象)

IOC作用:降低程序耦合
依賴關系管理:交給Spring完成
依賴注入數據有三種:
  基本類型
  其他bean類型(在bean.xml注解的)
  復雜類型/集合類型

 ①:構造函數注入

public class Student {
    private String name;
    private int age;
    private Date birthday;
    private Dog dog;
    //省略有參構造函數/get/set/toString
}

public class Dog {
    private String name;
    private String color;
    //省略有參構造函數/get/set/toString
}
實體類對象
 <!--配置Student對象-->
    <bean id="student" class="cn.xw.domain.Student">
        <constructor-arg name="name" value="張三"></constructor-arg>
        <constructor-arg name="age" value="25"></constructor-arg>
        <!--因為birthday是日期類型,所以我要引用下面的一個日期類型-->
        <constructor-arg name="birthday" ref="date"></constructor-arg>
        <!--因為dog是自定義對象Dog類型,所以我引用下面的Dog對象-->
        <constructor-arg name="dog" ref="dog"></constructor-arg>
    </bean>
    <!--配置Date對象-->
    <bean id="date" class="java.util.Date">
        <constructor-arg name="date" value="12345644556"></constructor-arg>
    </bean>
    <!--配置Dog對象-->
    <bean id="dog" class="cn.xw.domain.Dog">
        <constructor-arg name="name" value="大黃"></constructor-arg>
        <constructor-arg name="color" value="黃色"></constructor-arg>
    </bean>
    <!--
        constructor-arg:用來聲明構造函數里面的參數的
        ++++++++++++用來指定給那個參數賦值++++++++++++
        index:使用索引的方式來和構造函數列表匹配 下標0開始
        type:用來注入指定數據類型來匹配
        name:用來匹配構造函數里參數的名稱來賦值  最常用
        ++++++++++++設定值++++++++++++
        value:直接設置值即可
        rel:用來設置那些對象屬性,引用其它對象
    -->
applicationContext.xml配置文件
public class Client {
    public static void main(String[] args) throws SQLException, InterruptedException {
        //創建ApplicationContext對象
        ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
        //獲取對象
        Student student = app.getBean("student", Student.class);
        //打印對象
        System.out.println(student.toString());
        //打印結果:Student{name='張三', age=25, birthday=Sun May 24 05:20:44 CST 1970, dog=Dog{name='大黃', color='黃色'}}
    }
}
測試方法

②:set依賴注入

因為set注入必須要有屬性的全部set方法,而且還得提供一個無參的構造函數,所以對上面的實體類添加一個無參構造函數,接下來我對配置文件改造成set注入

<!--配置Student對象-->
    <bean id="student" class="cn.xw.domain.Student">
        <property name="name" value="張三"></property>
        <property name="age" value="25"></property>
        <!--因為birthday是日期類型,所以我要引用下面的一個日期類型-->
        <property name="birthday" ref="date"></property>
        <!--因為dog是自定義對象Dog類型,所以我引用下面的Dog對象-->
        <property name="dog" ref="dog"></property>
    </bean>
    <!--配置Date對象-->
    <bean id="date" class="java.util.Date">
        <property name="time" value="12345644556"></property>
    </bean>
    <!--配置Dog對象-->
    <bean id="dog" class="cn.xw.domain.Dog">
       <property name="name" value="大黃"></property>
        <property name="color" value="黃色"></property>
    </bean>
    <!--
       property:用於set注入
       注意:set注入是找到set方法后去除set字母把后面的字母全部換成小寫
       如:setName(String name)==>setName==>Name==>name==>最終找到name
    -->
set注入

③:復雜類型注入

 我們前面學習了普通的類型注入,但是如果遇到數組、集合、鍵值對怎么注入呢?接下來我就帶大家來討論一下!

public class Student {
    private String [] arrays;       //數組類型
    private List<String> list;      //有序集合
    private Set<String> sets;       //無序集合
    private Map<String,String> maps;//Map集合
    private Properties properties;  //properties鍵值對
    public void setArrays(String[] arrays) {
        this.arrays = arrays;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    public void setSets(Set<String> sets) {
        this.sets = sets;
    }
    public void setMaps(Map<String, String> maps) {
        this.maps = maps;
    }
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
    @Override
    public String toString() {
        System.out.println(arrays);
        System.out.println(list);
        System.out.println(sets);
        System.out.println(maps);
        System.out.println(properties);
        return null;
    }
}
實體類
<!--配置Student對象-->
    <bean id="student" class="cn.xw.domain.Student">
        <!--注入數組類型-->
       <property name="arrays">
          <array>
              <value>arraysA</value>
              <value>arraysB</value>
              <value>arraysC</value>
          </array>
       </property>
        <!--注入集合類型-->
        <property name="list">
            <list>
                <value>listA</value>
                <value>listB</value>
                <value>listC</value>
            </list>
        </property>
        <!--注入set類型-->
        <property name="sets">
            <set>
                <value>setA</value>
                <value>setB</value>
                <value>setC</value>
            </set>
        </property>
        <!--注入鍵值對類型-->
        <property name="maps">
            <map>
                <entry key="mapkeyA" value="mapValueA"></entry>
                <entry key="mapkeyB" value="mapValueB"></entry>
                <entry key="mapkeyC" value="mapValueC"></entry>
            </map>
        </property>
        <!--注入配置文件類型-->
        <property name="properties">
            <props>
                <prop key="propskeyA" >propsValueA</prop>
                <prop key="propskeyB" >propsValueB</prop>
                <prop key="propskeyC" >propsValueC</prop>
            </props>
        </property>
    </bean>
applicationContext.xml配置文件

注:Arrays、List、Set是一組 Map、Properties是一組,上面2組同類的標簽是可以相互替換的,因為類型都一樣,正常單列數據使用List,鍵值對數據使用Map即可

9:使用Spring基於XML完成對數據的CRUD操作(基於XML小總結)

本案例實現對學生表的CRUD操作,為了更好的體現出上面講的知識,我准備使用Spring基於XML開發,因為沒有涉及到web頁面,所以就建一個maven普通項目,不使用框架,其它技術有MySQL數據庫、dbutils工具包、C3P0連接池

資料導入:MySQL建表語句

public class Student {
    private int sid;            //主鍵id
    private String sname;       //姓名
    private String ssex;        //性別
    private int sage;           //年齡
    private double scredit;     //學分
    private double smoney;      //零花錢
    private String saddress;    //住址
    private String senrol;      //入學時間
    //因為簡單的單表CRUD就不涉及到外鍵
    //private int fid;            //外鍵 連接家庭表信息學生對家庭,一對一
    //private int tid;            //外鍵 連接老師信息 學生對老師,一對一
    //創建構造器/get/set/toString就不展示了
}
實體類
<dependencies>
        <!--mysql驅動-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>
        <!--工具類 操作數據庫-->
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.7</version>
        </dependency>
        <!--連接池-->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
        <!--Spring坐標-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        <!--單元測試-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
pom.xml坐標
#####接口
/**
 * 學生數據操作Dao接口
 * @author ant
 */
public interface StudentDao {
    //查詢全部學生
    List<Student> findAll();
    //查詢多個學生,根據姓名和地址模糊查詢
    List<Student> findByLikeNameAndLikeAddress(String name, String address);
    //查詢單個學生根據id
    Student findById(Integer id);
    //查詢學生總數
    Integer totalCount();
    //添加學生
    Integer add(Student student);
    //更新學生
    Integer update(Student student);
    //刪除學生
    Integer delete(Integer id);
}
+++++++++++++++++++++++++++++++++++++++++

######實現類
/**
 * 學生數據操作Dao實現類
 * @author ant
 */
public class StudentDaoImpl implements StudentDao {
    //聚合dbutils工具類
    private QueryRunner query;
    //有構造方法注入和set注入  這里選擇set注入 不修改無參構造器
    public void setQuery(QueryRunner query) {
        this.query = query;
    }

    //查詢全部學生
    public List<Student> findAll() {
        //初始化查詢后封裝的數據變量
        List<Student> students = null;
        //Sql語句
        String sql = "select * from student";
        //異常處理
        try {
            //執行sql語句並查詢數據
            students = query.query(sql, new BeanListHandler<Student>(Student.class));
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //返回數據
        return students;
    }

    //查詢多個學生,根據姓名和地址模糊查詢
    public List<Student> findByLikeNameAndLikeAddress(String name, String address) {
        List<Student> students = null;
        String sql = "select * from student where sname like ? and saddress like ? ";
        try {
            students = query.query(sql, new BeanListHandler<Student>(Student.class), name, address);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return students;
    }

    //查詢單個學生根據id
    public Student findById(Integer id) {
        Student student = null;
        try {
            student = query.query("select * from student where sid=?", new BeanHandler<Student>(Student.class), id);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return student;
    }

    //查詢學生總數
    public Integer totalCount() {
        Integer total = 0;
        try {
            total = query.query("select count(sid) from student", new ScalarHandler<Integer>());
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return total;
    }
    
    //添加學生
    public Integer add(Student student) {
        Integer code = 0;
        Object[] obj = {student.getSname(), student.getSsex(), student.getSage(), student.getScredit(),
                student.getSmoney(), student.getSaddress(), student.getSenrol()};
        String sql = "insert into student (sname,ssex,sage,scredit,smoney,saddress,senrol) values (?,?,?,?,?,?,?) ";
        try {
            code = query.update(sql, obj);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return code;
    }

    //更新學生
    public Integer update(Student student) {
        Integer code = 0;
        Object[] obj = {student.getSname(), student.getSsex(), student.getSage(), student.getScredit(),
                student.getSmoney(), student.getSaddress(), student.getSenrol(), student.getSid()};
        String sql = " update student set sname=?,ssex=?,sage=?,scredit=?,smoney=?,saddress=?,senrol=? where sid=? ";
        try {
            code = query.update(sql, obj);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return code;
    }

    //刪除學生
    public Integer delete(Integer id) {
        Integer code = 0;
        try {
            code = query.update("delete from student where sid=?", id);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return code;
    }
}
Dao接口及實現類
##### 接口

/**
 * 學生業務層Service 接口
 * @author ant
 */
public interface StudentService {
    //查詢全部學生
    List<Student> findAll();
    //查詢多個學生,根據姓名和地址模糊查詢
    List<Student> findByLikeNameAndLikeAddress(String name, String address);
    //查詢單個學生根據id
    Student findById(Integer id);
    //查詢學生總數
    Integer totalCount();
    //添加學生
    void add(Student student);
    //更新學生
    void update(Student student);
    //刪除學生
    void delete(Integer id);
}


+++++++++++++++++++++++++++++++++++++++++

######實現類

/**
 * 業務接口實現類 學生ServiceStudent
 * @author ant
 */
public class StudentServiceImpl implements StudentService {

    //聚合數據操作層
    private StudentDao studentDao;
    //我們這里使用set方法,方便Spring的注入對象
    public void setStudentDao(StudentDao studentDao) {
        this.studentDao = studentDao;
    }

    /**
     * 注:因為下面的這些數據都是簡單的CRUD操作,也沒有生命業務邏輯,所以直接調用即可
     */
    //查詢全部學生
    public List<Student> findAll() {

        return studentDao.findAll();
    }

    //查詢多個學生,根據姓名和地址模糊查詢
    public List<Student> findByLikeNameAndLikeAddress(String name, String address) {
        return studentDao.findByLikeNameAndLikeAddress(name, address);
    }

    //查詢單個學生根據id
    public Student findById(Integer id) {
        return studentDao.findById(id);
    }

    //查詢學生總數
    public Integer totalCount() {
        return studentDao.totalCount();
    }

    //添加學生
    public void add(Student student) {
        studentDao.add(student);
    }

    //更新學生
    public void update(Student student) {
        studentDao.update(student);
    }

    //刪除學生
    public void delete(Integer id) {
        studentDao.delete(id);
    }

}
Service接口及實現類
<?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">

    <!--把C3P0連接池放入容器中-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/demo_school"></property>
        <property name="user" value="root"></property>
        <property name="password" value="123"></property>
    </bean>

    <!--注冊dbutils里面的QueryRunner對象-->
    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
        <constructor-arg name="ds" ref="dataSource"></constructor-arg>
    </bean>

    <!--把StudentDao容器創建出來,使之聚合QueryRunner-->
    <bean id="studentDao" class="cn.xw.dao.impl.StudentDaoImpl">
        <property name="query" ref="queryRunner"></property>
    </bean>

    <!--把StudentService容器創建出來 並聚合StudentDao對象-->
    <bean id="studentService" class="cn.xw.service.impl.StudentServiceImpl">
        <property name="studentDao" ref="studentDao"></property>
    </bean>
</beans>
最重要的applicationContext.xml配置文件 基於XML的Spring
public class Client {
    //ApplicationContext容器
    private ApplicationContext app;
    //StudentService對象
    private StudentService ss;

    @Before
    public void init() {
        //初始化
        app = new ClassPathXmlApplicationContext("applicationContext.xml");
        ss = app.getBean("studentService", StudentService.class);
    }

    @After
    public void destroy() {
        //這里沒有關閉則不寫了
    }

    @Test   //查詢全部測試
    public void findAll() {
        List<Student> students = ss.findAll();
        for (Student student : students) {
            System.out.println(student);
        }
    }

    @Test   //模糊查詢測試
    public void findByLikeNameAndLikeAddress() {
        List<Student> students = ss.findByLikeNameAndLikeAddress("張%", "%六安%");
        for (Student student : students) {
            System.out.println(student);
        }
    }

    @Test   //id查找測試
    public void findById() {
        Student student = ss.findById(16);
        System.out.println(student);
    }

    @Test   //總數查詢測試
    public void totalCount() {
        Integer total = ss.totalCount();
        System.out.println("總數:" + total);
    }

    @Test   //添加測試
    public void add() {
        Student student = new Student(0, "王二虎", "男", 16, 55.5, 600.5, "安徽滁州", "2018-8-8");
        ss.add(student);
    }

    @Test   //更新測試
    public void update() {
        Student student = new Student(65, "王小二", "女", 21, 66.5, 666.5, "安徽蚌埠", "2019-8-8");
        ss.update(student);
    }

    @Test   //刪除測試
    public void delete() {
        ss.delete(65);
    }
}
測試

四:Spring之IOC詳細介紹(注解版)

1:簡單的注解開發框架搭建及測試

首先我來給大家展示一個最簡單的注解搭建,后面會一步一步詳解,最后會做一個案例,但是看了我下面的簡單注解操作會發現很多問題,不是說注解嗎?為什么還有配置文件,注入的一下方法就這么點,那注入復雜類型怎么辦呢?這里等等問題后面會慢慢解決

####### pom.xml配置文件
<dependencies>
        <!--導入Spring坐標-->
        <!--Spring注解開發依賴AOP包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        <!--單元測試-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>


++++++++++++++++++++++++++++++++++++++++++
##### Dao接口及實現
public interface StudentDao {
    //模擬添加學生
    void add();
}

//這里使用了Repository注解
@Repository(value="studentDao")
public class StudentDaoImpl implements StudentDao {
    //模擬添加學生
    public void add() {
        System.out.println("添加成功");
    }
}


++++++++++++++++++++++++++++++++++++++++++
##### Service接口及實現類
public interface StudentService {
    //模擬添加學生
    void add();
}

//這里使用了Service注解
@Service(value="studentService")
public class StudentServiceImpl implements StudentService {
    //這里使用了Autowired依賴注入
    //聚合StudentDao對象
    @Autowired
    private StudentDao studentDao;
    //添加學生
    public void add() {
        studentDao.add();
    }
}

++++++++++++++++++++++++++++++++++++++++++
##### applicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!--加載配置文件后掃描指定文件夾下的注解  -->
    <context:component-scan base-package="cn.xw"></context:component-scan>

</beans>


++++++++++++++++++++++++++++++++++++++++++
##### 測試
public class Client {
    @Test   //添加測試
    public void add() {
        ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
        StudentService studentService = app.getBean("studentService", StudentService.class);
        studentService.add();
    }
}
完成注解的簡單操作

2:@Component注解(和XML里面的Bean一樣)

  什么是@Component注解呢?大家在寫XML的時候是不是使用<bean id="xx" class="xx"></bean>,是說明把指定的對象放入容器中,其實@Component注解也一樣,也是告知把指定的對象放入容器中,但是注解比配置的容易,只需要把此注解寫在要裝入容器對象上即可,說白就是把資源讓Spring管理

@Component public class StudentDaoImpl implements StudentDao{
    內容省略
}
/**
 * 我好奇bean標簽里面還有id指明以后放入容器取出的key,那這個注解也沒有可咋搞?
 * 其實如果我們不寫默認id是當前類的類名首字母小寫 就變成了studentDaoImpl
 */
/////////////////////////////////////////////////////////////////////////////
/**
 * 默認的id名字太長了,所以我要給注解添加value屬性,就和bean里面的id一樣
 */ @Component(value="studentDao") public class StudentDaoImpl implements StudentDao{
    內容省略
}
/////////////////////////////////////////////////////////////////////////////
/**
 * 其實@Component 是有引申義注解的,為了讓注解有個語義性,內部也做了小調整,但整體沒太大差異
 * @Controller     注解表現層(Servlet)
 * @Service        注解業務層(Service)
 * @Repository     注解持久層(Dao)
 */

  @Controller(value="studentServlet")
  public class StudentServlet{}
  @Service(value="studentService")
  public class StudentServiceImpl implements StudentService{}
  @Repository(value="studentDao")
  public class StudentDaoImpl implements StudentDao{}
  @Component(value="student")
  public class Student{};

3:注解的依賴注入重要

①:@Autowired

在注解的入門案例中,大家有發現我使用了@Autowired標簽了嗎?其實這就是依賴注入標簽,使用特別簡單,只要在需要注入數據的屬性上使用此標簽就好了

@Repository(value="studentDao")
public class StudentDaoImpl implements StudentDao{}

@Service(value="studentService")
public class StudentServiceImpl implements StudentService{
    @Autowired private StudentDao studentDao;
}
//這樣我們就成功把value為studentDao的對象注入進去了  代碼片段(1)

上面的一段代碼是把StudentDaoImpl對象注入進去了,可是大家發現了嗎?我是怎么注入的,@Autowired沒有任何標識指向上面的對象,為什么會被注入上呢?那如果我有兩個StudentDaoImpl實現類后該直線誰呢?

@Repository(value="studentDaoA")
public class StudentDaoImplA implements StudentDao{}

@Repository(value="studentDaoB")
public class StudentDaoImplB implements StudentDao{}

@Service(value="studentService")
public class StudentServiceImpl implements StudentService{
    @Autowired
    private StudentDao studentDao;
}
//那這個又指向誰呢      代碼片段(2)

代碼片段(1)圖   由圖證明是可以注入對象的

 代碼片段(2)圖

 根據上面2中圖的第二張發現,自動注入也會有失敗的,原因是多個相同類型的類和屬性變量無法區分,因為Spring無法知道你具體要注入哪一個!但是針對第二張圖該如何解決呢?其實很簡單,只要把屬性變量名改為要注入類型的知道key,比如原來是studentDao,可以key容器里面只要studentDaoA和studentDaoB,所以我們自己明確一個即可,但是Spring幫我們解決了這個修改變量名的方式,它為我們提供了一個@Qualified注解

①:@Qualified

@Qualifiend注解就很好的解決了圖二的問題,它內部提供value屬性,讓開發者手動指定對應的key用來匹配,注意,它在注解屬性時必須要和@Autowired注解一起使用

@Repository(value="studentDaoA")
public class StudentDaoImplA implements StudentDao{}

@Repository(value="studentDaoB")
public class StudentDaoImplB implements StudentDao{}

@Service(value="studentService")
public class StudentServiceImpl implements StudentService{
    @Autowired @Qualifier(value = "studentDaoA") private StudentDao studentDao;
}

通過上面的標簽@Autowired和@Qualified,我們知道,要使用@Qualified注解時必須搭配@Autowird注解,它們2個搭配使用可以完成注入工作,但是你們有想嗎?每次都要寫這么2個注解太麻煩,沒有一個一步到位的標簽嗎?其實是有的,它就叫@Resource

②:@Resource

這個注解可以說挺容易的,一步到位,我們就簡單寫一下它吧,然后運行

@Service(value="studentService")
public class StudentServiceImpl implements StudentService {
    //聚合StudentDao對象
    @Resource(name="studentDao") private StudentDaoImpl studentDao;
    //添加學生
    public void add() {
        studentDao.add();
    }
}

問題:因為我用的是jdk9版本,而jdk9就已經棄用了這個注解,還有一個和這個相同錯誤的就是在Spring項目中引入@Resource注解時有紅色波浪線
解決:添加對應被棄用的坐標id
引申:@Resource這個注解位於java.xml.ws.annotation包是J2EE的一部分,但是J2EE在jdk9就被棄用了,並在JDK10刪除它,可以通過查詢這個包,看到里面的注解
<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
</dependency>

 ③:使用set方法注入

我們前3個都是在講為對象屬性注入,而且不用set方法即可注入,那如果要用set注入該如何注入呢?

@Service(value="studentService")
public class StudentServiceImpl implements StudentService {
    //聚合StudentDao對象
    private StudentDaoImpl studentDao;
    //注意:使用set方法注入時在方法參數里面必須指定在容器尋找的key,
    //也就是使用@Qualifier注解指示id,這個時候注解可以單獨使用,但是在屬性對象中必須配合@Autoired注解
    //使用set注入數據
    public void setStudentDao(@Qualifier(value="studentDao") StudentDaoImpl studentDao) {
        this.studentDao = studentDao;
    }
  
    //添加學生
    public void add() {studentDao.add();}
}

④:基本類型注入

基本類型只有8種:int、float、double、char、long、byte、short、boolean,接下來我就爭對幾個來完成基本類型注入,這里注意的是引用類型只能用上面的3種方法來完成注入,這里針對的是基本類型

//放入Spring容器
@Component(value="myTest")
public class MyTest {
    
    //使用Value注解依賴注入
    @Value(value="17")
    private byte age;
    @Value(value="52.6f")
    private float weight;
    @Value("6000.33")
    private double money;
    @Value("165")
    private int height;
    @Value("男")
    private char sex;
    @Value("true")
    private boolean isStudent;

    //打印語句
    @Override
    public String toString() {
        return "MyTest{" +
                "age=" + age +
                ", weight=" + weight +
                ", money=" + money +
                ", height=" + height +
                ", sex=" + sex +
                ", isStudent=" + isStudent +
                '}';
    }
}
//測試
class test{
    public static void main(String[] args) {
        ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
        MyTest test = (MyTest) app.getBean("myTest");
        System.out.println(test);
        //MyTest{age=17, weight=52.6, money=6000.33, height=165, sex=男, isStudent=true}
    }
}
基本類型注入

4:改變作用范圍和生命周期

 在前面的xml中介紹了如何改變容器里面的對象的作用范圍,默認是單例對象;<bean id="xx" class=“xx.xx.xxx” scope="prototype"></bean>這個就是設置多例的了

可是在注解中如何設置作用范圍呢?

@Service(value="studentService")
@Scope(value="singleton")  //這里我設置了單例 但默認不寫也是單例 多例是prototype public class StudentServiceImpl implements StudentService {
        ....................      
}

既然我們都會設置單例和多例了,可是怎么測試是單例還是多例呢?我就不比較它們的hashCode了,我這么來想,單例對象是根據容器銷毀則銷毀,而多例對象則由JVM垃圾回收器回收

@Service(value="studentService")
@Scope(value="singleton")
public class StudentServiceImpl implements StudentService {
    //聚合StudentDao對象
    @Resource(name="studentDao")
    private StudentDaoImpl studentDao;

    //添加學生
    public void add() {
        studentDao.add();
    }

    //初始化方法
    @PostConstruct
    public void init(){
        System.out.println("初始化成功");
    }
    //銷毀方法
    @PreDestroy
    public void destroy(){
        System.out.println("銷毀成功");
    }
}

++++++++++++++++++++++++++++++++++++++++++++++
 @Test   //添加測試
    public void add() {
        //因為ApplicationContext沒有關閉方法,所以我們使用子類
        ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
        StudentService studentService = app.getBean("studentService", StudentService.class);
        studentService.add();
        //關閉
        app.close();
    }


//使用xml配置方法<bean id="xxx" class="xx.xx.xx" init-method="xx" destroy-method="xxx"></bean>

/*其實上面的@PostConstruct 和@PreDestroy 兩個注解就相當於init-method="xx"和destroy-method="xxx"標簽屬性
但是要注意的是這2個注解和@Resource注解一樣必須要導入javax.annotation-api坐標,因為jdk9已經棄用了
還有的是我們也可以使用初始化方法達到注入屬性,不推薦知道就好
//初始化方法
    @PostConstruct
    public void init(){
        studentDao=new StudentDaoImpl();
        System.out.println("初始化成功");
    }
*/
初始化和銷毀注解及測試作用范圍

5:使用注解替代XML配置文件

 ①:@Configuration@ComponentScan

我在寫注解的基本入門案例中,大家是否記得,我還是用到了xml配置文件,用來告知Spring來開啟注解掃描,這顯然還是在用xml配置呀,但是接下來的注解中我要徹底消除xml配置文件

/**
 * @Configuration 注解說明當前類是一個配置類 和applicationContext.xml一樣
 */
@Configuration
public class SpringConfig {

}

現在我們使用注解@Configuration完成了一個配置類,但是這是一個空配置類,我們要完成注解開發就要對注解掃描,就和使用xml的<context:component-scan base-package="cn.xw"></context:component-scan>一樣,那我們就得使用到另一個注解@ComponentScan

/**
 * @Configuration 注解說明當前類是一個配置類 和applicationContext.xml一樣
 */
@Configuration
//推薦使用前五個掃描路徑,其實這5個都是一樣的 寫法不同
@ComponentScan("cn.xw")
//@ComponentScan(value="cn.xw")
//@ComponentScan(value={"cn.xw"})
//@ComponentScan(basePackages = "cn.xw")
//@ComponentScan(basePackages = {"cn.xw"})

//掃描類的class文件 不推薦 沒有掃描包方便
//@ComponentScan(basePackageClasses ={StudentDaoImpl.class, StudentServiceImpl.class} )

//設置多個路徑
// @ComponentScans(value={
//         @ComponentScan(value="cn.xw"),
//         @ComponentScan(value="xxx.xxx.x"),
//         @ComponentScan("xxx.xx.xx")
// })
public class SpringConfig {

}
/**
 *  用於設置單個路徑 @ComponentScan
 *  用於設置多個路徑 @ComponentScans
 *  在查詢@ComponentScan方法發現value和basePackages是一樣的,為什么呢?看下面
 *     @AliasFor("basePackages")
 *     String[] value() default {};
 *     @AliasFor("value")
 *     String[] basePackages() default {};
 * @AliasFor注解在相互引用這2個方法
 */
@ComponentScan注解詳解

6:@Bean注解的使用

  什么是@Bean注解呢?它有什么用呢?我先來舉個例子,比如我們自己寫的StudentDaoImpl類如果想放到Spring容器怎么辦呢?其實很容易,在StudentDaoImpl類上添加一個@Repository(value="studentDao")就可以了,那么問題來了,我現在有Date、SimpleDateFormat、String三個類都想放到Spring容器中,那么大家的第一反應是直接在那個類上面添加一個注解放入Spring容器中就可以啦,但是大家想想,這3個類不是我們自己的,都是jdk提供的,而且還是class文件,我們是無法修改的,所以Spring就為我們提供了一個@Bean注解用來把初始化好的對象放入容器中,下面我就帶大家看看把

  現在有個需求,要求創建一個Date對象並初始化放入容器中,SimpleDateFormat也是一樣初始化好格式放入容器,最后在創建一個Spring對象返回一個格式化好的Date日期返回

@Configuration
@ComponentScan("cn.xw")
public class SpringConfig {

    //創建一個Date對象並放入容器中 key指定為date
    @Bean(value="date")
    public Date createDate() {
        Date date = new Date(12564875956213L);
        return date;
    }

    //創建一個SimpleDateFormat對象放入容器中 key指示為simpleDateFormat
    @Bean(value = "simpleDateFormat")
    public SimpleDateFormat createFormat() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        return format;
    }
    
    //創建一個String對象放入容器 指定key為string
    //這里的方法有2個參數,具體是怎么映射上的后面說
    @Bean(value = "string")
    public String createDateString(Date time,SimpleDateFormat format){
        String dateString = format.format(time);
        return dateString;
    }
}

+++++++++++++++++++++++++++++++++++++++++
@Test   //添加測試
public void add() {
    ApplicationContext app=new AnnotationConfigApplicationContext(SpringConfig.class);
    String string = app.getBean("string", String.class);
    System.out.println(string); //打印結果:2368-03-02 03-19-16

}
@Bean注解解釋

 注意細節:@Bean注解屬性可以寫name或者value,因為它們2個互相引用,執行效果都是一樣的,用來標識放入IOC容器的id的key值,那么不寫name或者value屬性的話 默認方法名就為bean的id

 通過@Bean的介紹有個初步的了解,回到上個代碼,可看出createDateString(Date time,SimpleDateFormat format)方法要求接收2個參數,可是我在上面也沒指示怎么就被自動注入上了呢?其實這個原理和@Autowired自動注入一樣的

@Configuration
@ComponentScan("cn.xw")
public class SpringConfig {

    //創建一個Date對象並放入容器中 key指定為date
    @Bean(value="date")
    public Date createDate() {
        Date date = new Date(12564875956213L);
        return date;
    }
    //創建一個SimpleDateFormat對象放入容器中 key指示為simpleDateFormatA
    @Bean(value = "simpleDateFormatA")
    public SimpleDateFormat createFormatA() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        return format;
    }
    
    //創建一個SimpleDateFormat對象放入容器中 key指示為simpleDateFormatB
    @Bean(value = "simpleDateFormatB")
    public SimpleDateFormat createFormatB() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return format;
    }

    //創建一個String對象放入容器 指定key為string
    //這里的方法有2個參數,具體是怎么映射上的后面說
    @Bean(value = "string")
    public String createDateString(Date time,@Qualifier("simpleDateFormatB") SimpleDateFormat format){
        String dateString = format.format(time);
        return dateString;
    }
}

//方法參數自動注入和屬性自動注入一樣,假設現在的IOC容器中只要一個SimpleDateFormat類型的,那么Spring也是很
//智能的,直接把那個注入進去即可,因為不可能出現注入錯誤,但是出現兩個相同類型的,Spring就沒這么智能了,
//他要我們開發者告知它准確指向

//從上面的代碼可以看出創建了兩個SimpleDateFormat引用類型,我們就可以通過@Qualifier來指定,
//用法在數據注入詳細介紹過

7:獲取注解容器

  細心的人肯定會發現 我在去除ApplicationContext.xml配置文件后的測試類都使用了AnnotationConfigApplicationContext,原因是現在配置文件都是注解的了,再使用ClassPathXmlApplicationContext就獲取不到指定的配置類了,下面我給大家介紹一下

@Test   //添加測試
public void add() {
    //獲取注解類
    ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfig.class);
    String string = app.getBean("string", String.class);
    System.out.println(string);
    /**
     * ApplicationContext常見的獲取容器子類有3個 在ApplicationContext接口的實現類有介紹前2個
     * AnnotationConfigApplicationContext:用來加載讀取配置類,用來讀取注解配置類、
     * 參數可以是偽數組
     */
}

獲取規則(重要):如果參數直接寫到指定的配置類上的class,那個類可以不需要指定@Configuration注解,如果多個類都指定@Configuration注解,那么在獲取這些配置類的時候要把全部的class類通過偽數組放入方法參數中。如果配置類過多可以在指定一個主配置類上面標注@Configuration注解,其它的子類可以不指定@Configuration注解,但是在主配置類上要使用@Import注解來引用子配置類。

//主配置類 引用l子配置類
@Configuration
@ComponentScan("cn.xw")
@Import(value={SpringConfigB.class,SpringConfigD.class})
public class SpringConfig {

}
//子配置類
class SpringConfigB{}
//子配置類
class SpringConfigD{}

8:獲取配置文件數據

配置數據文件我相信大家在寫連接數據庫的四大數據了經常用到,可是在注解中怎么獲取配置連接數據呢?,接下來我就為大家來演示一個常用的操作

<!--Mysql驅動坐標-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.30</version>
        </dependency>
        <!--C3P0連接池坐標-->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
導入2個坐標
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/demo_school
jdbc.username=root
jdbc.password=123
dataSource.properties配置文件
@Configuration
@ComponentScan("cn.xw")
@PropertySource("classpath:dataSource.properties")
public class SpringConfig {
    
    //注入下面4個屬性 單個value可以省去直接寫值
    @Value(value = "${jdbc.driver}")
    private String driver;
    @Value(value = "${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    
    @Bean(value="dataSource")
    public DataSource createDataSourcePool() {
        //創建C3P0連接池
        ComboPooledDataSource ds = new ComboPooledDataSource();
        try {
            //設置連接池
            ds.setDriverClass(driver);
            ds.setJdbcUrl(url);
            ds.setUser(username);
            ds.setPassword(password);
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        return ds;
    }
}

注:@PropertySource注解是配置類路徑下文件,還有一個@PropertySources注解是配置多個,里面可以寫多個@PropertySource,和@ComponentScans一樣寫法格式

9:Spring整合Junit測試(重要

我們在前面的時候寫測試類都是使用ApplicationContext app=new xxxx(xxx);這樣的寫法無疑使程序測試變的麻煩,那我們就不能對對屬性進行注入然后運行嗎,就像下面的這段代碼操作

public class Client {
    //屬性注入
    @Autowired
    @Qualifier(value = "studentService")
    private StudentService ss;

    @Test   //添加測試
    public void add() {
        //調用保存方法
        ss.add();
    }
}

  大家看上面的一段代碼也沒什么錯,正常的注入,然后調用Service方法,可是程序在運行的時候拋了一個空指針異常,而且還是明確在ss.add()這一行,那就說明了StudentService屬性壓根就沒有注入上,為什么呢?你們首先想一想,我之前在運行測試的時候會執行到ApplicationContext app=new xxx(xxx),這句話一執行就會找到那個配置文件/配置類,然后讀取那個配置文件后,把讀取到的數據放到一個IOC容器中,這樣我們在后面使用依賴注入的時候就可以去IOC容器取到相對於的類型,可是現在我們把那個ApplicationContext app=new xxx(xxxx)去除了,肯定就找不到了,那么怎么辦呢?其實我們需要的是程序能為我們自動創建容器,一旦程序可以自動幫我們創建了容器,那么我們的問題也就解決了。

  其實junit是無法實現幫我們自動創建IOC容器的,因為它的管理范疇就是單單的測試,而且它壓根也就不知道你使用的是Spring框架,更別說創建容器了,但是好在junit為外界提供了一個注解,可以讓我們指定替換掉它的運行器,這時候我們就要把Spring框架的test的jar包里的SpringJUnit4ClassRunner類放入到運行器中替換,這樣就完成了有Spring管理junit了。

<!--Spring的測試坐標-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
<!--單元測試-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

<!--maven導入Spring-test坐標必須要導入junit坐標,而且導入Spring-test坐標的話,junit坐標必須為4.1.2或以上-->
導入對應坐標
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) //用於指示注解類位置
//@ContextConfiguration(locations = "classpath:applicationContext.xml") //用於指示配置文件為了 類路徑下
public class Client {
    //屬性注入
    @Autowired
    @Qualifier(value = "studentService")
    private StudentService ss;

    @Test   //添加測試
    public void add() {
        //調用保存方法
        ss.add();
    }
}
/**
 * @RunWith(SpringJUnit4ClassRunner.class)
 * 更改運行器,交由Spring管理Junit
 * 
 * @ContextConfiguration(classes = SpringConfig.class)
 * 告知Spring我們的配置文件/配置類放到哪了
 */

10:注解開發總結案例對學生單表CRUD操作

 在學習完前面的注解知識后,我接下來就帶大家完成一個純注解的CRUD操作,還是和XML的總結案例一樣,也是那幾個技術,mysql建表語句也是和之前的一樣。

<dependencies>
        <!--mysql驅動坐標-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>

        <!--c3p0連接池坐標-->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>

        <!--dbutils工具類坐標-->
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.7</version>
        </dependency>

        <!--junit單元測試坐標-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <!--Spring-context主要坐標-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>

        <!--Spring-test測試坐標-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>

        <!--annotation坐標-->
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.2</version>
        </dependency>
    </dependencies>
pom.xml坐標文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/demo_school
jdbc.username=root
jdbc.password=123
jdbc.properties數據庫連接資源文件
public class Student {

    private int sid;            //主鍵id
    private String sname;       //姓名
    private String ssex;        //性別
    private int sage;           //年齡
    private double scredit;     //學分
    private double smoney;      //零花錢
    private String saddress;    //住址
    private String senrol;      //入學時間
    //因為簡單的單表CRUD就不涉及到外鍵
    //private int fid;            //外鍵 連接家庭表信息學生對家庭,一對一
    //private int tid;            //外鍵 連接老師信息 學生對老師,一對一
    //創建構造器/get/set/toString就不展示了
}
Student實體類
//當前是主配置類
@Configuration
@ComponentScan(value = "cn.xw")
@Import(value={DataSourceConfig.class})
public class SpringConfig {

    //創建對象QueryRunner放入IOC容器  因為連接QueryRunner有多個操作 所以設置多例
    @Bean("queryRunner")
    @Scope(value = "prototype")
    public QueryRunner createQueryRunner(@Qualifier("dataSource") DataSource dataSource) {
        QueryRunner queryRunner=new QueryRunner(dataSource);
        return queryRunner;
    }
}

+++++++++++++++++++++++++++++++++++++++++

//獲取配置文件注解
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfig {

    //注入數據從配置文件獲取四大數據
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    //創建c3p0連接池並返回一個DataSource
    @Bean("dataSource")
    public DataSource createDataSource() {
        ComboPooledDataSource ds = new ComboPooledDataSource();
        try {
            ds.setDriverClass(driver);
            ds.setJdbcUrl(url);
            ds.setUser(username);
            ds.setPassword(password);
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        return ds;
    }
}
配置類兩個(其中一個主配置類)
/**
 * 學生數據操作Dao接口
 * @author ant
 */
public interface StudentDao {
    //查詢全部學生
    List<Student> findAll();
    //查詢多個學生,根據姓名和地址模糊查詢
    List<Student> findByLikeNameAndLikeAddress(String name, String address);
    //查詢單個學生根據id
    Student findById(Integer id);
    //查詢學生總數
    Integer totalCount();
    //添加學生
    Integer add(Student student);
    //更新學生
    Integer update(Student student);
    //刪除學生
    Integer delete(Integer id);
}



+++++++++++++++++++++++++++++++++++++++++

/**
 * 學生數據操作Dao實現類
 * @author ant
 */
@Repository("studentDao")
public class StudentDaoImpl implements StudentDao {
    //聚合dbutils工具類
    @Resource(name = "queryRunner")
    private QueryRunner query;

    //查詢全部學生
    public List<Student> findAll() {
        //初始化查詢后封裝的數據變量
        List<Student> students = null;
        //Sql語句
        String sql = "select * from student";
        //異常處理
        try {
            //執行sql語句並查詢數據
            students = query.query(sql, new BeanListHandler<Student>(Student.class));
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //返回數據
        return students;
    }

    //查詢多個學生,根據姓名和地址模糊查詢
    public List<Student> findByLikeNameAndLikeAddress(String name, String address) {
        List<Student> students = null;
        String sql = "select * from student where sname like ? and saddress like ? ";
        try {
            students = query.query(sql, new BeanListHandler<Student>(Student.class), name, address);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return students;
    }

    //查詢單個學生根據id
    public Student findById(Integer id) {
        Student student = null;
        try {
            student = query.query("select * from student where sid=?", new BeanHandler<Student>(Student.class), id);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return student;
    }
    //查詢學生總數
    public Integer totalCount() {
        Integer total = 0;
        try {
            total = Integer.parseInt(query.query("select count(sid) from student", new ScalarHandler<Object>()).toString());
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return total;
    }
    //添加學生
    public Integer add(Student student) {
        Integer code = 0;
        Object[] obj = {student.getSname(), student.getSsex(), student.getSage(), student.getScredit(),
                student.getSmoney(), student.getSaddress(), student.getSenrol()};
        String sql = "insert into student (sname,ssex,sage,scredit,smoney,saddress,senrol) values (?,?,?,?,?,?,?) ";
        try {
            code = query.update(sql, obj);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return code;
    }
    //更新學生
    public Integer update(Student student) {
        Integer code = 0;
        Object[] obj = {student.getSname(), student.getSsex(), student.getSage(), student.getScredit(),
                student.getSmoney(), student.getSaddress(), student.getSenrol(), student.getSid()};
        String sql = " update student set sname=?,ssex=?,sage=?,scredit=?,smoney=?,saddress=?,senrol=? where sid=? ";
        try {
            code = query.update(sql, obj);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return code;
    }
    //刪除學生
    public Integer delete(Integer id) {
        Integer code = 0;
        try {
            code = query.update("delete from student where sid=?", id);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return code;
    }
}
dao數據操作接口及實現類
/**
 * 學生業務層Service 接口
 * @author ant
 */
public interface StudentService {
    //查詢全部學生
    List<Student> findAll();
    //查詢多個學生,根據姓名和地址模糊查詢
    List<Student> findByLikeNameAndLikeAddress(String name, String address);
    //查詢單個學生根據id
    Student findById(Integer id);
    //查詢學生總數
    Integer totalCount();
    //添加學生
    void add(Student student);
    //更新學生
    void update(Student student);
    //刪除學生
    void delete(Integer id);
}

+++++++++++++++++++++++++++++++++++++++++

/**
 * 業務接口實現類 學生ServiceStudent
 * @author ant
 */
@Service("studentService")
public class StudentServiceImpl implements StudentService {
    //聚合數據操作層
    @Autowired
    @Qualifier("studentDao")
    private StudentDao studentDao;

    /**
     * 注:因為下面的這些數據都是簡單的CRUD操作,也沒有生命業務邏輯,所以直接調用即可
     */
    //查詢全部學生
    public List<Student> findAll() {
        return studentDao.findAll();
    }
    //查詢多個學生,根據姓名和地址模糊查詢
    public List<Student> findByLikeNameAndLikeAddress(String name, String address) {
        return studentDao.findByLikeNameAndLikeAddress(name, address);
    }
    //查詢單個學生根據id
    public Student findById(Integer id) {
        return studentDao.findById(id);
    }
    //查詢學生總數
    public Integer totalCount() {
        return studentDao.totalCount();
    }
    //添加學生
    public void add(Student student) {
        studentDao.add(student);
    }
    //更新學生
    public void update(Student student) {
        studentDao.update(student);
    }
    //刪除學生
    public void delete(Integer id) {
        studentDao.delete(id);
    }
}
service業務處理接口級實現類
//設置運行器和配置類位置
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class Client {
    //注解注入
    @Autowired
    @Qualifier(value="studentService")
    private StudentService ss;

    @Test   //查詢全部測試
    public void findAll() {
        List<Student> students = ss.findAll();
        for (Student student : students) {
            System.out.println(student);
        }
    }
    @Test   //模糊查詢測試
    public void findByLikeNameAndLikeAddress() {
        List<Student> students = ss.findByLikeNameAndLikeAddress("張%", "%六安%");
        for (Student student : students) {
            System.out.println(student);
        }
    }
    @Test   //id查找測試
    public void findById() {
        Student student = ss.findById(16);
        System.out.println(student);
    }
    @Test   //總數查詢測試
    public void totalCount() {
        Integer total = ss.totalCount();
        System.out.println("總數:" + total);
    }
    @Test   //添加測試
    public void add() {
        Student student = new Student(0, "王二虎", "男", 16, 55.5, 600.5, "安徽滁州", "2018-8-8");
        ss.add(student);
    }
    @Test   //更新測試
    public void update() {
        Student student = new Student(65, "王小二", "女", 21, 66.5, 666.5, "安徽蚌埠", "2019-8-8");
        ss.update(student);
    }
    @Test   //刪除測試
    public void delete() {
        ss.delete(65);
    }
}
測試類 Spring整合Junit

五:Spring IOC 總結

  在學了上面的Spring IOC后,知道了Spring IOC為了程序解耦,使用過XML和注解兩種方法完成表的CRUD操作,可是這個兩個有什么優勢呢?或者說哪個更好呢?其實2個都差不多,xml配置是文件更清晰可見,但是特別繁瑣,一大段一大段的標簽要寫,好多都是重復性的寫標簽,但是注解開發呢,使效率上有提高,但是呢,如果大量的使用注解后使程序的可讀性變差;比如在類上面使用注解,使之放到IOC容器中,這樣如果出現多個類后,后期要查看當前類是否有放入容器中,只要點卡此類查看,但是使用xml呢?我直接新建一個xml專門存放要存放容器的對象,這樣清晰可讀,所以總結一下使用注解和xml搭配使用會有好的效果!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM