SpringIOC基礎知識總結
阿新 • • 發佈:2020-11-23
[TOC]
![image-20201122163930311](https://typora-files.oss-cn-beijing.aliyuncs.com/file/image-20201122163930311.png)
### 1.BeanFactory和ApplicationContext的區別:
**BeanFactory**是Spring框架中IOC容器的頂層介面,它只是用來定義一些基礎功能,定義一些基礎規範,而**ApplicationContext**是它的一個子介面,所以ApplicationContext是具備BeanFactory提供的全部功能。
通常我們稱BeanFactory為SpringIOC的基礎容器,ApplicationContext是容器的高階介面,比如BeanFactory擁有更多的功能,比如說國際化支援和資源訪問(xml、java配置類)等等。
### 2.例項化bean的三種方式:
#### ⽅式⼀:使⽤⽆參建構函式
在預設情況下,它會通過反射調⽤⽆參建構函式來建立物件。如果類中沒有⽆參建構函式,將建立失敗。
``` xml
```
#### ⽅式⼆:使⽤靜態⽅法建立
在實際開發中,我們使⽤的物件有些時候並不是直接通過建構函式就可以創建出來的,它可能在建立的過程中會做很多額外的操作。此時會提供⼀個建立物件的⽅法,恰好這個⽅法是static修飾的⽅法,即是此種情況。
例如,我們在做Jdbc操作時,會⽤到`java.sql.Connection`接⼝的實現類,如果是mysql資料庫,那麼⽤的就是JDBC4Connection,但是我們不會去寫 `JDBC4Connection connection = newJDBC4Connection()` ,因為我們要註冊驅動,還要提供URL和憑證資訊,⽤ `DriverManager.getConnection` ⽅法來獲取連線。
那麼在實際開發中,尤其早期的項⽬沒有使⽤Spring框架來管理物件的建立,但是在設計時使⽤了⼯⼚模式解耦,那麼當接⼊spring之後,⼯⼚類建立物件就具有和上述例⼦相同特徵,即可採⽤此種⽅式配置。
``` xml
```
#### ⽅式三:使⽤例項化⽅法建立
此種⽅式和上⾯靜態⽅法建立其實類似,區別是⽤於獲取物件的⽅法不再是static修飾的了,⽽是類中的⼀ 個普通⽅法。此種⽅式⽐靜態⽅法建立的使⽤⼏率要⾼⼀些。
在早期開發的項⽬中,⼯⼚類中的⽅法有可能是靜態的,也有可能是⾮靜態⽅法,當是⾮靜態⽅法時,即可採⽤下⾯的配置⽅式:
``` xml
```
### 3.Bean的作用範圍和生命週期
#### 3.1作用範圍——scope
![image-20201122175934570](https://typora-files.oss-cn-beijing.aliyuncs.com/file/image-20201122175934570.png)
經常使用的有**singleton**和**prototype**:
``` xml
```
測試:
``` java
//===
@org.junit.Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
System.out.println("accountDao:"+accountDao);
AccountDao accountDao1 = (AccountDao) applicationContext.getBean("accountDao");
System.out.println("accountDao1:"+accountDao1);
}
//得出結果為:
accountDao:com.lagou.edu.dao.impl.JdbcAccountDaoImpl@58cbafc2
accountDao1:com.lagou.edu.dao.impl.JdbcAccountDaoImpl@58cbafc2
//同一個物件
```
``` java
//===
@org.junit.Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
System.out.println("accountDao:"+accountDao);
AccountDao accountDao1 = (AccountDao) applicationContext.getBean("accountDao");
System.out.println("accountDao1:"+accountDao1);
}
//得出結果為:
accountDao:com.lagou.edu.dao.impl.JdbcAccountDaoImpl@75d3a5e0
accountDao1:com.lagou.edu.dao.impl.JdbcAccountDaoImpl@74d1dc36
//不是同一個物件
```
#### 3.2生命週期
- **singleton(預設)單例:IOC容器只有一個該類物件**
- 物件出生:當容器建立時,物件就被建立了
- 物件活著:只要容器在,物件就一直活著
- 物件死亡:當容器銷燬時,物件就被銷燬了
一句話總結:單例模式的bean物件生命週期與容器相同
- **prototype (多例)原型:每次使用該類的物件(getBean),都返回一個新的物件**
- 物件出生:當使用物件時建立新的物件例項
- 物件活著:只要物件在使用中,就一直活著
- 物件死亡:當物件長時間不用時,被java的垃圾回收器回收了
一句話總結:多例模式的bean物件,spring框架只負責建立,不負責銷燬
**init-method**屬性:⽤於指定bean物件的初始化⽅法,此⽅法會在**bean物件裝配後調⽤**。必須是⼀個⽆參⽅法。
**destory-method**屬性:⽤於指定bean物件的銷燬⽅法,此⽅法會在bean**物件銷燬前執⾏**。**它只能為scope是singleton時起作⽤。**
![image-20201122181648307](https://typora-files.oss-cn-beijing.aliyuncs.com/file/image-20201122181648307.png)
### 4.DI依賴注入的xml配置
#### 4.1 set方法注入
set注入使用`property`標籤,如果注入的是另外一個bean使用`ref`屬性,如果注入的是普通值使用`value`屬性
``` xml
```
#### 4.2 建構函式注入
- **根據有參建構函式引數索引**:
``` xml
```
- **根據有參建構函式引數名稱:**
``` xml
```
#### 4.3 複雜型別
``` xml
array1
array2
set1
set2
value1
value2
```
### 5.DI依賴注入的註解和xml相結合實現方式
>哪些bean定義在xml中,哪些bean的定義使用註解?
>
>第三方jar中的bean定義在xml
>
>自己開發的bean使用註解
我是用Druid連線池,那麼它屬於第三方jar,所以我就在配置檔案中配置
``` xml
```
然後在使用它的地方使用註解:
![image-20201122230057797](https://typora-files.oss-cn-beijing.aliyuncs.com/file/image-20201122230057797.png)
#### 5.1 @Autowired——按照型別注入
按照型別注入:如下帶程式碼,它會在容器中找到一個型別為`AccoutDao`的物件注入進來
``` java
@Service("transferService")//不指定也可以,變成了類名的首字母小寫
public class TransferServiceImpl implements TransferService {
//@Autowired 按照型別注入
@Autowired
private AccountDao accountDao;
//可以加在屬性和set方法上,如果加在屬性上,set方法就不需要了
// public void setAccountDao(AccountDao accountDao) {
// this.accountDao = accountDao;
// }
```
> **如果AccountDao有多個實現類 ,且多個實現類都配置在了IOC容器中,怎麼辦?**
#### 5.2 @Qualifier("具體id")——指定具體的id
``` java
@Service("transferService")
public class TransferServiceImpl implements TransferService {
//@Autowired 按照型別注入,如果按照型別無法唯一鎖定物件,可以結合@Qualifier("具體的id")
@Autowired
@Qualifier("accountDao")
private AccountDao accountDao;
```
#### 5.3 @Resource
@Resource 註解由J2EE 提供,需要導⼊包 **javax.annotation.Resource**。 (JDK11預設移除,jdk8可以直接使用)
@Resource 預設按照 ByName ⾃動注⼊。
``` java
public class TransferService {
@Resource
private AccountDao accountDao;
@Resource(name="studentDao")
private StudentDao studentDao;
@Resource(type="TeacherDao")
private TeacherDao teacherDao;
@Resource(name="manDao",type="ManDao")
private ManDao manDao;
}
```
如果同時指定了 **name** 和 **type**,則從Spring上下⽂中找到唯⼀匹配的bean進⾏裝配,找不到則丟擲異常。
如果指定了 **name**,則從上下⽂中查詢名稱(id)匹配的bean進⾏裝配,找不到則丟擲異常。
如果指定了 **type**,則從上下⽂中找到類似匹配的唯⼀bean進⾏裝配,找不到或是找到多個,都會丟擲異常。
如果既**沒有指定**name,⼜沒有指定type,則⾃動按照byName⽅式進⾏裝配;
**注意:**
@Resource 在 Jdk 11中已經移除,如果要使⽤,需要單獨引⼊jar包
``` xml
javax.annotation
javax.annotation-api
1.3.2
```
#### 5.4 註解掃描
##### 5.4.1 引入名稱空間——context
``` xml
```
##### 5.4.2 開啟註解掃描
```xml
```
#### 6.其他
引入外部資原始檔:
```xml
```
最終的配置檔案只留下了一個第三方jar
``` xml
```
### 6.DI依賴注入,純註解模式
不要xml配置檔案,從java配置類啟動
1. 新建SpringCofig類
2. 使用註解**@Configuration** 標識當前類是一個配置類
3. 使用註解**@ComponentScan({"com.lagou.edu"})** 代替` `進行註解掃描
4. 使用註解**@PropertySource({"classpath:jdbc.properties"})** 代替` `引入外部資原始檔
5. 使用**@Bean** 將⽅法返回物件加⼊SpringIOC 容器
6. **@Value** 對變數賦值,可以直接賦值,也可以使⽤ ${} 讀取資源配置⽂件中的資訊
7. 還可以使用**@Import** 引⼊其他配置類
``` java
//@Configuration 標識當前類是一個配置類
@Configuration
@ComponentScan({"com.lagou.edu"})
@PropertySource({"classpath:jdbc.properties"})
public class SpringConfig {
@Value("${jdbc.driver}")
private String driverClassName;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean("dataSource")
public DataSource creatDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(driverClassName);
druidDataSource.setUrl(url);
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
return druidDataSource;
}
}
```
#### 6.1啟動
##### 6.1.1 JavaSE:
``` java
@org.junit.Test
public void test(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
System.out.println(accountDao);
}
```
##### 6.1.2 JavaWeb:
1. 配置web.xml檔案
``` xml
Archetype Created Web Application
contextClass
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
contextConfigLocation
com.lagou.edu.SpringConfig
org.springframework.web.context.ContextLoaderListener
`