Spring的IOC以及DI
阿新 • • 發佈:2018-11-06
Spring引入
* spring 是什麼? Spring是分層的 Java SE/EE應用 full-stack 輕量級開源框架,以 IoC(Inverse Of Control: 反轉控制)和 AOP(Aspect Oriented Programming:面向切面程式設計)為核心,提供了展現層 Spring MVC 和持久層 Spring JDBC 以及業務層事務管理等眾多的企業級應用技術,還能整合開源世界眾多 著名的第三方框架和類庫,逐漸成為使用最多的Java EE 企業應用開源框架。 * 程式的耦合 耦合:程式之間的依賴關係 包括了類與類之間的依賴,方法之間的依賴 解耦:降低程式之間的依賴關係,提升程式的靈活性與可擴充套件性 實際開發中:應該做到編譯期不依賴,執行時才會依賴 解耦的思路: 第一步:使用反射來建立物件,從而避免使用new關鍵字 第二步:通過讀取配置檔案來獲取要建立的物件全限定類名 * 三層架構程式碼中存在的問題 業務層呼叫持久層的時候的new dao的介面 在表現層呼叫業務層的時候new service的介面 解決辦法: 使用工廠模式解耦(一個建立bean物件的工廠) Bean 1. Bean:在計算機英語中,有可重用元件的含義 2. JavaBean:用java語言編寫的可重用元件 JavaBean > 實體類 3. POJO(Plain Ordinary Java Object)即普通Java類 4. 可以認為POJO就一個不帶方法而單純承載資料實體Bean;EJB是一個包含了POJO的超集、 包含POJO之外的,具有方法、實現、功能這一群元件。 方法: 1. 一個配置檔案配置service與dao的內容(xml/properties) 2. 通過讀取配置檔案來獲取要建立的物件全限定類名,反射載入 3.優化:使用單例
Spring的IOC(Inversion Of Control)
* IOC:控制反轉 簡單理解:讓spring來控制物件 * 入門案例: 1. 匯入依賴 2. 建立配置檔案,匯入約束,並寫入相關的bean標籤(配置id與class) 3. 從容器中獲取容器物件 3.1 先獲取容器 ApplicationContext ac = new ClassPathXmlApplicationContext("配置檔案") 3.2 從容器中根據id或者name獲取bean物件 User user = ac.getBean("user", User.class); System.out.println(user);//User{userName='null', age=null, birthday=null} * ApplicationContext的三個常用的實現類 ClassPathXmlApplicationContext:它可以載入類路徑下的配置文的件,要求配置檔案必須在類路徑下,不在就載入不了 FileSystemXmlApplicationContext:它可以載入磁碟任意路徑下的配置檔案 (必須有訪問許可權) AnnotationConfigApplicationContext:它是用於讀取註解的配置 * 核心容器的兩個介面引發出的問題 ApplicationContext:(單例物件試用),多使用此介面 它在構建核心容器的時候,建立物件採取的是立即載入的方式,也就是說,只要一讀取完配置檔案就馬上 就建立配置檔案中的配置的物件 BeanFactory:(多例物件適用) 它在構建核心容器的時候,採取的策略是延遲載入的方式,也就是說,什麼時候根據id獲取物件了,什麼時候才會 真正的建立物件 * Spring對bean的管理細節 1. 建立bean的三種方式: 1.1 第一種方式:使用預設建構函式建立 在spring的配置檔案中使用bean標籤,配置id與class屬性之後,且沒有其他屬性和標籤時 採用的就是預設建構函式建立bean物件,測試如果類中沒有預設建構函式,則物件無法建立 <bean id="service" class="com.qin.service.impl.IUserServiceImpl"></bean> 1.2 第二種方式:使用普通工廠中的方法來建立物件(使用某個類中的方法建立物件,並存入spring容器) <bean id="instanceFactory" class="com.qin.factory.instanceFactory"></bean>(要先有物件才能呼叫方法) <bean id="serviceFactory" class="com.qin.factory.instanceFactory" factory-method="getAccount"> </bean> 1.3 第三種方式:使用工廠中的靜態方法建立物件(使用某個類中的靜態方法建立物件,並存入spring容器) <bean id="serviceFactory" class="com.qin.factory.StaticFactory" factory-method="getAccount"> </bean> 靜態方法是不需要物件的,是可以通過全類名呼叫的,所以不需要物件 2. bean的作用範圍 bean標籤的scope屬性 作用:用於指定bean 的作用範圍 取值: singleton:單例的(預設值) prototype:多例的 request:作用於wen應用的請求範圍 session:作用於wen應用的會話範圍 global-session:作用於叢集環境的會話範圍(全域性會話範圍),當不是叢集的時候,相當於session 3. bean物件的生命週期 單例物件: 出生:當容器建立時候物件出生 存在:只要容器在,物件就一直活著 死亡:容器銷燬,物件消亡 總結:單例物件的生命週期和容器相同 多例物件: 出生:當使用物件時,spring框架為我們建立 存在:物件還在使用的過程中就一直存活 死亡:當物件長時間不用,且沒有別的物件引用時,由java的垃圾回收器回收
Spring依賴注入:DI(依賴關係的維護)
* 能注入的資料:三類 1. 基本型別和string : 2. 其他bean型別(在配置檔案中或者註解配置過的bean) 3. 複雜型別/集合型別 * 注入的方式:有三種 1. 使用建構函式提供(不常用) 使用的標籤:constructor-arg 標籤出現的位置:bean標籤的內部 標籤的屬性: type:用於指定要注入的資料的資料型別,該資料型別也是建構函式中某個或某些引數的型別 index:用於指定要注入的資料給建構函式中指定索引位置的引數賦值,索引的位置是從0開始的 name:用於指定給建構函式中指定名稱的引數賦值(常用) =============以上三個用於指定給建構函式中的哪個引數賦值================== value:用於提供基本型別和string型別的資料 ref:用於指定其他的bean型別資料.他指的就是在spring的核心容器中出現過的bean物件 優勢: 在獲取bean物件時,注入資料是必須的操作,否則物件無法建立成功. 弊端: 改變了bean物件的例項化方式,使我們在建立物件時,如果不使用這些資料也必須提供. 2. 使用set方法提供(常用) * 首先必須有set方法 涉及的標籤:property 出現的位置:bean標籤的內部 標籤的屬性: name:用於指定注入時呼叫的set方法名稱 value:用於提供基本型別和string型別的資料 ref:用於指定其他的bean型別資料.他指的就是在spring的核心容器中出現過的bean物件 優勢:建立物件時沒有明確的限制,可以直接使用預設建構函式 弊端:如果某個成員必須有值,則獲取物件是有可能set方法沒有執行 3. 使用註解提供 * 示例: 1. 建構函式注入 <bean id="userDao" class="com.qin.dao.impl.IUserDaoImpl"> <constructor-arg name="userName" value="sakura"></constructor-arg> <constructor-arg name="age" value="18"></constructor-arg> <constructor-arg name="birthday" ref="date"></constructor-arg> </bean> <bean id="date" class="java.util.Date"></bean> 2. 使用set方法注入 <bean id="userDao1" class="com.qin.dao.impl.IUserDaoImpl1"> <property name="age" value="19"></property> <property name="userName" value="tom"></property> <property name="birthday" ref="date"></property> </bean> <bean id="date" class="java.util.Date"></bean> 3. 對集合屬性進行set方式注入 <bean id="userDao2" class="com.qin.dao.impl.IUserDaoImpl2"> <property name="myStrs"> <array> <value>string</value> <value>string</value> <value>string</value> </array> </property> <property name="myList"> <list> <value>list</value> <value>list</value> <value>list</value> </list> </property> <property name="mySet"> <set> <value>set</value> <value>set</value> <value>set</value> </set> </property> <property name="myMap"> <map> <entry key="map1"> <value>map1</value> </entry> <entry key="map2" value="map2"></entry> <entry key="map3" value="map3"></entry> </map> </property> <property name="myProps"> <props> <prop key="prop">123</prop> <prop key="prop">123</prop> <prop key="prop">123</prop> </props> </property> </bean>
Spring的基於註解開發
* IOC在XML的配置:<bean id="accountService" class="com.qin.service.impl.AccountService" scope=""
init-method="" destory-method="">
<property name="" value="" |ref=""></property>
</bean>
* 註解分類:
1. 用於建立物件的
它們的作用就和xml配置中編寫一個<bean>標籤實現的功能是一樣的
@Component:
作用:
用於把當前類物件存入Spring容器中
屬性:
value:用於指定bean中的id.當我們不寫時,他的預設值是當前類名的,且首字母小寫
@Controller:一般用在表現層
@Service:一般用在業務層
@Repository:一般用在持久層
以上三個註解的作用和屬性與Component是一模一樣的
他們三個是spring為我們提供明確的三層使用的註解,使我們的三層物件更加清晰
在xml檔案的配置:
<context:component-scan base-package="com.qin"></context:component-scan>
作用:告知spring在建立容器時要掃描的包,配置所需要的標籤不是beans約束中,而是在context
的名稱空間和約束中
約束配置:
<?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">
2. 用於注入資料的
它們的作用就和在xml配置檔案中的bean標籤中寫一個<property>標籤的作用是一樣的
@Autowired
作用:(自動按照型別注入)
如果ioc容器中有唯一的一個bean物件型別和要注入的變數型別匹配,就可以注入成功
如果ioc容器中沒有任何bean型別和要注入的變數型別一致,將會注入失敗
如果ioc容器中有多個bean型別和要注入的變數型別一致,會先根據型別尋找,再根據變數名找
出現位置:
變數上,方法上(在set方法上也可以使用);
細節:
在使用註解注入時,set方法就不是必須的
@Qualifier
* 配合@Autowired使用
* 也可以存在於引數上,配合指定構造中要傳遞的bean物件
作用:
在按照類中注入的基礎之上再按照名稱注入.他在給類成員注入時不能單獨使用,但是在給方法引數注入時可以
屬性:
value:用於指定注入bean的id
@Resource
* jdk1.9不能使用
作用:
直接按照bean的id注入,它可以單獨使用
屬性:
name:用於指定bean 的id
* 以上三個注入都只能注入其他bean型別,而基本型別和string型別無法使用上述註解實現,集合型別也可以用Autowired實現
@Value
作用:
用於注入基本型別和string型別的資料
屬性:
value:用於指定資料的值.他可以使用spring和spEL(也就是spring的el表示式)
spEL的寫法:#{表示式}
#{}:去容器中找id為花括號內容對應的值
${}:去配置檔案中讀取花括號對應的值
3. 用於改變作用範圍的
它們的作用就和在xml配置檔案中的bean標籤中使用scope屬性實現的功能是一樣的
@Scope
作用:
用於指定bean的作用範圍
屬性:
value:指定範圍的取值.常用取值:singleton prototype
4. 和生命週期相關
它們的作用就和在xml配置檔案中的bean標籤中使用init-method和destory-method的作用是一樣的
@PreDestroy
作用:
用於指定銷燬方法
@PostConstruct
作用:
用於指定初始化方法
* spring的新註解(可以使用純註解的形式開發)
* 建立一個類.替換核心配置檔案
@Configuration
作用:
指定當前類是一個配置類
細節:
當配置類作為AnnotationConfigApplicationContext物件建立的引數時,可以不寫此註解
但不是任何時候都可以不寫(把註解檔案分開寫,另一個沒有讀的配置檔案必須寫)
@ConponentScan
作用:
用於通過註解指定spring在建立容器時要掃面的包
屬性:
value:它和basePackage的作用是一樣的,都是用於指定建立容器時要掃面的包
我們使用次註解就等同於在xml中配置了:
<context:component-scan base-package="com.qin"></context:component-scan>
@Bean
作用:
用於把當前方法的的返回值作為bean物件存入spring的ioc容器中
屬性:
name:用於指定bean的id,當不寫時,預設值是當前方法的名稱
細節:
當我們使用註解來配置方法時,如果方法有引數,spring框架會去容器中查詢有沒有可用的bean物件,查詢的方式和
@Autowired註解的作用一樣的
@Import
作用:
用於匯入其他的配置類
屬性:
value:用於指定其他配置類的位元組碼檔案
當我們使用import的註解之後,有import註解的類就是父配置類,而匯入的都是子配置類
@PropertySource
作用:
用於指定properties檔案的位置
屬性:
value:指定檔案的名稱以及檔案的路徑
關鍵字:classpath,表示類路徑下
例子:
@PropertySource("classpath:JdbcConfig.properties")
*沒有xml檔案時測試就要修改ApplicationContext的建立方式
ApplicationContext ac = new AnnotationConfigApplicationContext("被@Configuration註解過的類".class)
抽取配置資料庫檔案
1.抽取檔案:
jdbcConfig.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=root
2. 在Spring的配置檔案中配置:
<context:property-placeholder location="jdbcConfig.properties"></context:property-placeholder>
使用註解的配置為:
@PropertySource("classpath:jdbcConfig.properties")
3. 在原來的配置檔案中使用Spring的el表示式
${}來表示
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password"></property>