1. Spring載入Bean流程解析
spring的bean生命周期其實最核心的分為4個步驟,只要理清三個關鍵的步驟,其他的只是在這三個細節中添加不同的細節實現,也就是spring的bean生命周期:
-.();
這個階段允許在Bena進行實例化之前,允許開發者自定義邏輯,如返回一個代理對象。不過需要注意的是假如在這個階段返回了一個不為null的實例,spring就會中斷後續的過程。
-BeanPostProcessor.postProcessAfterInstantiation();
這個階段是Bean實例化完畢後執行的後處理操作,所有在初始化邏輯、裝配邏輯之前執行
該方法在bean初始化方法前被調用,Spring AOP的底層處理也是通過實現BeanPostProcessor來執行代理邏輯的
自定義屬性值 該方法允許我們進行對對象中的屬性進行設置,假如在某些業務中,一個對象的某些屬性為null,但是不能顯示為null,比如顯示0或者其他的固定數值,我們就可以在這個方法實現中將null值轉換為特定的值
可以在這個方法中進行bean的實例化之後的處理,比如我們的自定義註解,對依賴對象的版本控制自動路由切換。比如有一個服務依賴了兩種版本的實現,我們如何實現自動切換呢?這時候可以自定義一個路由註解,假如叫@RouteAnnotaion,然後實現BeanPostProcessor介面,在其中通過反射拿到自定義的註解@RouteAnnotaion再進行路由規則的設定。
容器正式渲染完畢,開始啟動階段,bean已經在spring容器的管理下,程序可以隨時調用
spring會將所有的bean銷毀,實現的bean實例被銷毀的時候釋放資源被調用
2. spring基於註解的普通類怎麼調用@Services註解的service方法
1、添加util方法:
package com.hzc.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* 普通類調用Spring註解方式的Service層bean
* Created by HZC on 2015/10/21.
*/
public class SpringBeanFactoryUtils implements ApplicationContextAware {
private static ApplicationContext appCtx;
/**
* 此方法可以把ApplicationContext對象inject到當前類中作為一個靜態成員變數。
*
* @param applicationContext ApplicationContext 對象.
* @throws BeansException
* @author hzc
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
appCtx = applicationContext;
}
/**
* 獲取ApplicationContext
*
* @return
* @author hzc
*/
public static ApplicationContext getApplicationContext() {
return appCtx;
}
/**
* 這是一個便利的方法,幫助我們快速得到一個BEAN
*
* @param beanName bean的名字
* @return 返回一個bean對象
* @author hzc
*/
public static Object getBean(String beanName) {
return appCtx.getBean(beanName);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2、在spring的配置文件.xml中添加
<bean id="springBeanFactoryUtils" class="com.haier.util.SpringBeanFactoryUtils"/>
1
1
3、service方法
package com.hzc.service.impl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* Created by HZC on 2015/10/20.
*/
@Service("ckPayoffService")
public class CKPayoffServiceImpl implements ICKPayoffOrderService {
private static final Logger log = LoggerFactory.getLogger(CKPayoffServiceImpl.class);
/**
* 測試
*
* @author HZC
* @createDate 2015-10-21
*/
@Override
@Transactional
public void calculatePayoff() {
System.out.println("--------------------------gogogogogo---------------");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
4、使用
CKPayoffServiceImpl ckps = (CKPayoffServiceImpl) SpringBeanFactoryUtils.getBean("ckPayoffService");
ckps.calculatePayoff();
1
2
1
2
在普通類中就可以調用service實例方法了,執行calculatePayoff方法,列印「————————–gogogogogo—————」
3. spring注入bean,怎麼直接調用其方法
一般需要在static方法里調用注入進來的service,因為是靜態方法,所以必須聲明該service也必須是static的,這時候你會發現注入不進來,會報null指針,這個時候需要使用 @PostConstruct來解決。
4. 註解bean的用途
1、@Component註解表明一個類會作為組件類,並告知Spring要為這個類創建bean。
2、@Bean註解告訴Spring這個方法將會返回一個對象,這個對象要注冊為Spring應用上下文中的bean。通常方法體中包含了最終產生bean實例的邏輯。
兩者的目的是一樣的,都是注冊bean到Spring容器中。
區別:
@Component(@Controller、@Service、@Repository)通常是通過類路徑掃描來自動偵測以及自動裝配到Spring容器中。
而@Bean註解通常是我們在標有該註解的方法中定義產生這個bean的邏輯。
@Component 作用於類,@Bean作用於方法。
總結:
@Component和@Bean都是用來注冊Bean並裝配到Spring容器中,但是Bean比Component的自定義性更強。可以實現一些Component實現不了的自定義載入類。
5. Spring之Bean
spring 容器就是一個工廠,而bean 是工廠里的每一個產品,而這個工廠生產什麼樣的產品,是依賴於配置文件的聲明。
一、
注冊的方式有兩種:
1、xml配置文件
2、java based 配置
二、Bean的命名規則
默認,spring是以@Bean聲明的方法名作為bean的名稱,spring容器集中管理Bean的實例化,Bean實例可以通過BeanFactory的getBean(string beanName) 方法得到。
從上圖可以看出,
name:用於為bean指定別名,如果需要為Bean實例指定多個別名,可以在name 屬性中使用逗號,冒號和空格來分隔多個別名
autowire:是否按名稱或是類型來注入依賴的對象
initMethod: 在初始化完後,調用的方法
destroyMethod: bean在銷毀時調用的方法
三、Bean的作用域
通過@Scope來聲明
1、singleton:單例模式
2、Prototype:原型模式
3、request:對於 每次http 請求,bean都會產生一個新的實例,只有在web 應用中才會生效
4、session 對於 每次HttpSession時會產生一個新的實例,只有在web 應用中才會生效
5、global session ,只有在portlet context中有效
比較常用到的是singleton和prototype,java在創建實例,要進行內存申請,銷毀實例時,要垃圾回收,這些都會導致系統開銷的增加,因此prototype作用域的bean在創建、銷毀代價會比較大,而singleton的bean實例,一旦創建,就可以重復使用
四、Bean的生命周期
1、@Bean註解的內容:通過配置initMethod和destroyMethod方法
2、bean的介面:BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean這些介面,@PostConstruct,@PreDestroy
測試如下
bean的聲明:
日誌輸出:
我們來看下Bean的初始化是怎麼進行的
1、是調用 實現了相應Aware介面的方法
2、調用Bean實例的後置處理器BeanPostProcessor
這里有兩個方法 ,Before和After....,分別在initMethod方法前後被調用
3、調用Bean實例的InitializingBean介面和@Bean的initMethod,InitializingBean介面是優於initMethod的
4、實例銷毀