[Spring+SpringMVC+Mybatis]框架學習筆記(二):Spring-IOC-DI

上一章:[Spring+SpringMVC+Mybatis]框架學習筆記(一):SpringIOC概述
下一章:[Spring+SpringMVC+Mybatis]框架學習筆記(三):Spring實現JDBChtml

第2章 Spring-IOC-DI

Spirng的IOC(控制反轉)是經過依賴注入(dependency injection)來實現的。java

優勢:面試

  • 大量減小了對象的建立和管理,使代碼層次更加清晰;
  • Spring的IOC容器是一個輕量級的容器,沒有入侵性(不依賴容器的API),不須要實現一些特殊的接口,這是一個合理設計的基本要求;
  • 鼓勵咱們面向接口編程;
  • 減小代碼的耦合,將耦合的部分推到了配置文件中,若是他們的關係發生了改變,只須要修改配置文件;
  • 提供了aop聲明式的服務能力。

2.1 基於xml配置文件的注入

基於xml文件配置的注入:spring

  • 構造函數注入
  • setter方法注入
  • 特定接口注入(用的少,省略)

前兩種詳見第1章.數據庫

2.1.1 常見pojo類屬性的注入

pojo類:沒有實現任何接口和繼承任何父類的簡單的java類編程

1)bean數組

package com.steven.spring.sysmgr.entity;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 用於測試pojo對象常見屬性的注入
 * @author chenyang
 *
 */
public class User {
    private String strValue;
    private int intValue;
    private List listValue;
    private Set setValue;
    private String[] strArrayValue;
    private Map mapValue;
    public String getStrValue() {
        return strValue;
    }
    public void setStrValue(String strValue) {
        this.strValue = strValue;
    }
    public int getIntValue() {
        return intValue;
    }
    public void setIntValue(int intValue) {
        this.intValue = intValue;
    }
    public List getListValue() {
        return listValue;
    }
    public void setListValue(List listValue) {
        this.listValue = listValue;
    }
    public Set getSetValue() {
        return setValue;
    }
    public void setSetValue(Set setValue) {
        this.setValue = setValue;
    }
    public String[] getStrArrayValue() {
        return strArrayValue;
    }
    public void setStrArrayValue(String[] strArrayValue) {
        this.strArrayValue = strArrayValue;
    }
    public Map getMapValue() {
        return mapValue;
    }
    public void setMapValue(Map mapValue) {
        this.mapValue = mapValue;
    }
}

2)配置文件applicationContext-property.xmlapp

<?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">
    
    <bean id="user" class="com.steven.spring.sysmgr.entity.User">
        <property name="strValue" value="abc"/>
        <property name="intValue" value="123"/>
        <property name="listValue">
            <list>
                <value>list1</value>
                <value>list2</value>
                <value>list3</value>
            </list>
        </property>
        
        <property name="setValue">
            <set>
                <value>set1</value>
                <value>set2</value>
                <value>set3</value>
            </set>
        </property>
        
        <property name="strArrayValue">
            <list>
                <value>strArray1</value>
                <value>strArray2</value>
                <value>strArray3</value>
            </list>
        </property>
        
        <property name="mapValue">
            <map>
                <entry key="key1" value="map1"></entry>
                <entry key="key2" value="map2"></entry>
                <entry key="key3" value="map3"></entry>
            </map>
        </property>
        
    </bean>
</beans>

3)測試類框架

package com.steven.spring.sysmgr.action;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.steven.spring.sysmgr.entity.User;
/**
 * 測試bean的屬性的注入
 * @author chenyang
 *
 */
public class PropertyDITest {
    @Test
    public void testPropertyDI(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext-property.xml");
        User user = (User) ac.getBean("user");
        
        System.out.println("strValue : " + user.getStrValue());
        System.out.println("intValue : " + user.getIntValue());
        System.out.println("listValue : " + user.getListValue());
        System.out.println("setValue : " + user.getSetValue());
        System.out.println("strArrayValue : " + user.getStrArrayValue());
        System.out.println("mapValue : " + user.getMapValue());
    }
}

測試結果:函數

strValue : abc
intValue : 123
listValue : [list1, list2, list3]
setValue : [set1, set2, set3]
strArrayValue : [Ljava.lang.String;@71def8f8
mapValue : {key1=map1, key2=map2, key3=map3}

2.1.2 bean的scope屬性

bean的scope屬性表明bean對象的做用域,scope=「singleton/prototype」

  • singleton 僅初始化一次,建立一個實例 A a = new A() 至關於單例模式
  • prototype 每次對bean的訪問都會從新建立一個新的實例 至關於多例模式

1)配置文件applicationContext-scope.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!-- scope屬性表示單例/多例,屬性值singleton(默認)/prototype-->
    <bean id="userOther" class="com.steven.spring.sysmgr.entity.UserOther" scope="prototype"></bean>
</beans>

2)測試類(實體類UserOther略)

package com.steven.spring.sysmgr.action;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.steven.spring.sysmgr.entity.UserOther;
/**
 * 測試bean的scope屬性
 * @author chenyang
 *
 */
public class ScopeDITest {
    private ApplicationContext ac;
    
    @Before
    public void init(){
        ac = new ClassPathXmlApplicationContext("applicationContext-scope.xml");
    }
    
    @Test
    public void testScopeDI(){
        
        UserOther userOther1 = (UserOther) ac.getBean("userOther");
        UserOther userOther2 = (UserOther) ac.getBean("userOther");
        
        System.out.println(userOther1.toString());
        System.out.println(userOther2.toString());
        System.out.println(userOther1 == userOther2);
        
    }
    
}

2.1.3 bean的延遲加載

  • 在bean標籤裏面寫入lazy-init=」false/true」,當爲false時,容器啓動時加載;當爲true時,啓動時不加載,使用時加載;
  • 在bean的頭文件裏面寫入default-lazy-init=」true」 表明整個配置文件的對象都是延遲加載的。

1)配置文件applicationContext-lazyInit.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!-- 延遲加載lazy-init屬性,默認值false -->   
    <!-- 這裏爲了模擬出延遲加載的效果,故意將class值寫錯 --> 
    <bean id="userAnOther" class="com.steven.spring.sysmgr.entity.UserAnotherError" lazy-init="true"></bean>
</beans>

2)測試類

package com.steven.spring.sysmgr.action;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * 測試bean的scope屬性
 * @author chenyang
 *
 */
public class LazyInitTest {
    private ApplicationContext ac;
    
    @Before
    public void init(){
        ac = new ClassPathXmlApplicationContext("applicationContext-lazyInit.xml");
    }
    
    @Test
    public void testLazyInit(){
        //若lazy-init爲false,這句不會打印,直接報錯;若爲true,這句打印後報錯
        System.out.println("---------容器已啓動--------");
        ac.getBean("userAnOther");
        
    }
    
}

2.1.4 bean的自動裝配(autowire)

spring能夠自動的向bean中注入依賴 ----> 自動裝配(autowire),其底層都是經過setter方式注入:

  • byName 定義的依賴的bean名稱須要與類中引用的名稱一致,就會匹配依賴關係;
  • byType 經過定義的依賴bean 的類型來進行匹配.

ps:建議不要在配置文件裏面用自動裝配,雖然能夠減小配置文件,可是不利於維護。這裏講主要是後面註解部分要用到。

1)服務類UserService和Dao類IUserDao、UserDaoImplJdbc和UserDaoImplOther與第1章中例子中相同,這裏略

2)配置文件applicationContext-autowire.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!-- 自動裝配autowire,它有兩個屬性值:byName/byType -->
    
    <bean id="userDao" class="com.steven.spring.sysmgr.dao.impl.UserDaoImplJdbc"></bean>
    
    <bean id="userDaoImplOther" class="com.steven.spring.sysmgr.dao.impl.UserDaoImplOther" autowire-candidate="false"></bean>
    
    <!-- byName: 它是根據類UserService中所依賴的類的引用的名稱(userDao),在本配置文件中去尋找對應的bean的id,這裏即爲userDao -->
    <bean id="userServiceByName" class="com.steven.spring.sysmgr.service.UserService" autowire="byName"></bean>
    
    <!-- byType: 它是根據類UserService中所依賴的類的類型來匹配,只要類型一致便可(包含實現或子類),那麼這裏就會匹配兩個,就會報錯,所以就須要在不需匹配的bean標籤中加上    autowire-condidate="false",該屬性默認值爲true  -->
    <bean id="userServiceByType" class="com.steven.spring.sysmgr.service.UserService" autowire="byType"></bean>
</beans>

3) 測試類

package com.steven.spring.sysmgr.action;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.steven.spring.sysmgr.service.UserService;

public class AutoWireTest {
    ApplicationContext ac;
    
    @Before
    public void init(){
        ac = new ClassPathXmlApplicationContext("applicationContext-autowire.xml");
    }
    
    //測試自動裝配byName方式
    @Test
    public void testAutoWireByName(){
        UserService userService = (UserService)ac.getBean("userServiceByName");
        userService.loginUser("abc", "123");
    }
    
    //測試自動裝配byType方式
    @Test
    public void testAutoWireByType(){
        UserService userService = (UserService)ac.getBean("userServiceByType");
        userService.loginUser("abc", "123");
    }
}

2.2 配置文件的加載方式

2.2.1 單個配置文件

  • 根據類的相對路徑加載:
    ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml");
  • 根據文件的絕對路徑加載:
    ApplicationContext ac = new FileSystemXmlApplicationContext("E:\\spring02-IOC-DI\\\src\\\applicationContext.xml");

2.2.2 多個配置文件

1)測試類:

package com.steven.spring.sysmgr.action;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 測試不一樣方式加載多個spring配置文件
 * @author chenyang
 *
 */
public class ConfigFilesLoadTest {
    @Test
    public void testConfigFilesLoad(){
        //方式1: 按照單個配置文件逐個加載,此處略
        
        //方式2:羅列或數組
        //羅列的方式
        /*ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml",
                "applicationContext-property.xml",
                "applicationContext-scope.xml");*/
        
        //數組的方式
        /*String[] configFiles = new String[]{
                "applicationContext.xml",
                "applicationContext-property.xml",
                "applicationContext-scope.xml"};
        ApplicationContext ac = new ClassPathXmlApplicationContext(configFiles);*/
        
        //方式3:字符串匹配的方式
        /*ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext*.xml");*/
        
        //方式4:總配置文件的方式
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext-all.xml");
        
    }
}

2)總配置文件applicationContext-all.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <import resource="applicationContext.xml"/>
    <import resource="applicationContext-property.xml"/>
    <import resource="applicationContext-scope.xml"/>
</beans>

2.3 基於註解的注入

  • 引入jar包:spring-aop-4.2.1.RELEASE.jar
  • 在xml配置文件里加入約束
  • 在xml配置文件裏定義掃描須要用到的包的路徑
  • 在須要註解的bean對象前面加入註解標識符
    • @Component("") 通用型
    • @Service("") 通常用於聲明服務類
    • @Repository("") 通常用於聲明DAO類
    • @Controller("") 通常用於聲明控制類(springMVC/struts2 action/controller)
    • @Scope(""singleton/prototype") 聲明單例/多例
  • 聲明依賴關係
    • @Resource 默認是用byName的方式注入,實在找不到,就用byType方式
    • @Autowired 默認是用byType的方式注入,但若是遇到多個,而後用byName的方式
    • @Qualifier("") 指定須要的對象的名稱,需與Autowired配合使用,不能單獨使用

注意(面試):

註解方式通常原則上不須要設置setter 方法,但通常都寫上。由於當咱們經過配置文件的方式進行了部分DI,若沒有setter 方法,就會報異常。

這裏借用第1章中的例子。

1)配置文件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 http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
    <context:component-scan base-package="com.steven.spring.sysmanage"></context:component-scan>
</beans>

2)服務類

package com.steven.spring.sysmanage.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.steven.spring.sysmanage.dao.IUserDao;

/**
 * 用於用戶登陸、增刪改查的服務類
 * @author Administrator
 *
 */

//說明當前類是一個組件,至關於在配置文件中加入的對應的bean標籤
//@Component("userService")
@Service("userService")
public class UserService {
    @Autowired //默認是用byType的方式注入,但若是遇到多個,而後用byName的方式
    //@Qualifier("userDaoOther") //指定須要的類的名稱,需與Autowired配合使用,不能單獨使用
    //@Resource  //默認是用byName的方式注入,實在找不到,就用byType方式
    IUserDao userDao;
    
    public void setUserDao(IUserDao userDao) {
        this.userDao = userDao;
    }
    
    /**
     * 經過調用與數據庫交互的UserDao裏面的loginUser方法,判斷是否驗證成功
     * @param userName
     * @param password
     * @return
     */
    public boolean loginUser(String userName, String password){
        boolean flag = false;
        flag = userDao.loginUser(userName, password);
        return flag;
    }
    
}

3)DAO類

package com.steven.spring.sysmanage.dao.impl;

import org.springframework.stereotype.Repository;

import com.steven.spring.sysmanage.dao.IUserDao;

//@Component("userDao")
@Repository("userDao")
public class UserDao implements IUserDao {
    public boolean loginUser(String userName, String password) {
        System.out.println("這是經過JDBC進行登陸驗證的DAO方法");
        return true;
    }

}

package com.steven.spring.sysmanage.dao.impl;

import org.springframework.stereotype.Repository;

import com.steven.spring.sysmanage.dao.IUserDao;

//@Component("userDaoOther")
@Repository("userDaoOther")
public class UserDaoOther implements IUserDao {
    public boolean loginUser(String userName, String password) {
        System.out.println("這是經過其它方式進行登陸驗證的DAO方法");
        return true;
    }

}

4)測試類

package com.steven.spring.sysmanage.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.steven.spring.sysmanage.service.UserService;
/**
 * 測試使用註解的方式實現DI
 * @author Administrator
 *
 */
public class AnnotationTest {
    @Test
    public void testDI(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) ac.getBean("userService");
        userService.loginUser("abc", "123");
        
    }
    
}

上一章:[Spring+SpringMVC+Mybatis]框架學習筆記(一):SpringIOC概述
下一章:[Spring+SpringMVC+Mybatis]框架學習筆記(三):Spring實現JDBC

相關文章
相關標籤/搜索