目錄
?文章來源地址http://www.zghlxwxcb.cn/news/detail-511777.html
1. Spring IOC容器
1.1 Spring IOC 容器的設(shè)計
1.1.1 BeanFactory
1.1.2 ApplicationContext
1.2 Spring Bean的生命周期
1.2.1 BeanDefinition
1.2.2 InstantiationAwareBeanPostProcessor和BeanPostProcessor
1.2.3 測試生命周期
?文章來源:http://www.zghlxwxcb.cn/news/detail-511777.html
1. Spring IOC容器
1.1 Spring IOC 容器的設(shè)計
Spring IOC 容器的設(shè)計主要是基于BeanFactory和ApplicationContext兩個接口,其中ApplicationContext是BeanFactory的子接口之一,換句話說BeanFactory是Spring IOC容器所定義的最頂層接口,而ApplicationContext是其高級接口之一,并且對于BeanFactory功能做了許多有用的擴展,所以在絕大部分的工作場景中,都會使用ApplicationContext作為Spring IOC 容器,如下圖所示:
?首先我們定義一個User實體類:
public class User {
String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
'}';
}
}
1.1.1 BeanFactory
BeanFactory的使用注冊Bean對象以及獲取Bean對象代碼如下:
DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
RootBeanDefinition rootBeanDefinition=new RootBeanDefinition(User.class);
beanFactory.registerBeanDefinition("user",rootBeanDefinition);
System.out.println(beanFactory.getBean("user",User.class));
1.1.2 ApplicationContext
ApplicationContext的使用注冊Bean對象以及獲取Bean對象代碼如下:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(User.class);
applicationContext.refresh();
System.out.println(applicationContext.getBean("user", User.class));
1.2 Spring Bean的生命周期
Spring 容器可以管理 singleton 作用域 Bean 的生命周期,在此作用域下,Spring 能夠精確地知道該 Bean 何時被創(chuàng)建,何時初始化完成,以及何時被銷毀。
而對于 prototype 作用域的 Bean,Spring 只負責(zé)創(chuàng)建,當(dāng)容器創(chuàng)建了 Bean 的實例后,Bean 的實例就交給客戶端代碼管理,Spring 容器將不再跟蹤其生命周期。每次客戶端請求 prototype 作用域的 Bean 時,Spring 容器都會創(chuàng)建一個新的實例,并且不會管那些被配置成 prototype 作用域的 Bean 的生命周期。
生命周期主要是為了了解Spring IOC容器初始化和銷毀Bean的過程,通過對它的學(xué)習(xí)就可以知道如何在初始化和銷毀的時候加入自定義的方法,以滿足特定的需求。如下圖:
?
從上圖可以看到,Spring IoC容器對Bean 的管理還是比較復(fù)雜的,Spring loC容器在執(zhí)行了初始化和依賴注入后,會執(zhí)行一定的步驟來完成初始化,通過這些步驟我們就能自定義初始化,而在Spring IoC 容器正常關(guān)閉的時候,它也會執(zhí)行一定的步驟來關(guān)閉容器,釋放資源。除需要了解整個生命周期的步驟外,還要知道這些生命周期的接口是針對什么而言的,首先介紹生命周期的步驟。
1.?如果 Bean 實現(xiàn)了接口 BeanNameAware的setBeanName方法,那么它就會調(diào)用這個方法。
2.?如果 Bean 實現(xiàn)了接口 BeanFactoryAware 的 setBeanFactory方法,那么它就會調(diào)用這個方法。
3.?如果 Bean實現(xiàn)了接口 ApplicationContextAware 的 setApplicationContext方法,且
Spring loC容器也必須是一個ApplicationContext 接口的實現(xiàn)類,那么才會調(diào)用這個方法,否則是不調(diào)用的。
4.?如果 Bean 實現(xiàn)了接口 BeanPostProcessor 的 postProcessBeforeInitialization方法,那么它就會調(diào)用這個方法。
5 .如果 Bean實現(xiàn)了接口BeanFactoryPostProcessor的afterPropertiesSet方法,那么它就會調(diào)用這個方法。
6.?如果 Bean自定義了初始化方法,它就會調(diào)用已定義的初始化方法。
7.?如果Bean 實現(xiàn)了接口 BeanPostProcessor 的postProcessAfterInitialization方法,完成了這些調(diào)用,這個時候Bean 就完成了初始化,那么 Bean就生存在Spring loC的容器中了,使用者就可以從中獲取 Bean的服務(wù)。
8.?當(dāng)服務(wù)器正常關(guān)閉,或者遇到其他關(guān)閉 Spring loC 容器的事件,它就會調(diào)用對應(yīng)的方完成Bean 的銷毀,其步驟如下:
? ? ? ? 如果Bean實現(xiàn)了接口 DisposableBean 的 destroy方法,那么就會調(diào)用它。
? ? ? ? 如果定義了自定義的銷毀方法,那么就會調(diào)用它。
1.2.1 BeanDefinition
Spring容器啟動的過程中,會將Bean解析成Spring內(nèi)部的BeanDefinition結(jié)構(gòu)。不管是是通過xml配置文件的<Bean>標(biāo)簽,還是通過注解配置的@Bean,還是@Compontent標(biāo)注的類,還是掃描得到的類,它最終都會被解析成一個BeanDefinition對象,最后我們的Bean工廠就會根據(jù)這份Bean的定義信息,對bean進行實例化、初始化等等操作。
你可以把BeanDefinition丟給Bean工廠,然后Bean工廠就會根據(jù)這個信息幫你生產(chǎn)一個Bean實例,拿去使用。
BeanDefinition里面里面包含了bean定義的各種信息,如:bean對應(yīng)的class、scope、lazy信息、dependOn信息、autowireCandidate(是否是候選對象)、primary(是否是主要的候選者)等信息。
?RootBeanDefinition類:表示根bean定義信息,通常bean中沒有父bean的就使用這種表示。
ChildBeanDefinition類:表示子bean定義信息,如果需要指定父bean的,可以使用ChildBeanDefinition來定義子bean的配置信息,里面有parentName屬性,用來指定父bean的名稱。
GenericBeanDefinition類:通用的bean定義信息,既可以表示沒有父bean的bean配置信息,也可以表示有父bean的子bean配置信息,這個類里面也有parentName屬性,用來指定父bean的名稱。
ConfigurationClassBeanDefinition類:表示通過配置類中@Bean方法定義bean信息
可以通過配置類中使用@Bean來標(biāo)注一些方法,通過這些方法來定義bean,這些方法配置的bean信息最后會轉(zhuǎn)換為ConfigurationClassBeanDefinition類型的對象。
AnnotatedBeanDefinition接口:表示通過注解的方式定義的bean信息。
BeanDefinitionBuilder:構(gòu)建BeanDefinition的工具類
1.2.2 InstantiationAwareBeanPostProcessor和BeanPostProcessor
?
InstantiationAwareBeanPostProcessor實際上繼承了BeanPostProcessor接口。InstantiationAwareBeanPostProcessor作用于實例化階段的前后,BeanPostProcessor作用于初始化階段的前后。如下圖:
?BeanPostProcessor是一個接口,還有很多子接口,這些接口中提供了很多方法,spring在bean生命周期的不同階段,會調(diào)用BeanPostProcessor中的一些方法,來對生命周期進行擴展,bean生命周期中的所有擴展點都是依靠這個集合中的BeanPostProcessor來實現(xiàn)的。該接口提供了兩個函數(shù):postProcessBeforeInitialzation( Object bean, String beanName ) 當(dāng)前正在初始化的bean對象會被傳遞進來,我們就可以對這個bean作任何處理。 這個函數(shù)會先于InitialzationBean執(zhí)行,因此稱為前置處理。 所有Aware接口的注入就是在這一步完成的。postProcessAfterInitialzation( Object bean, String beanName ) 當(dāng)前正在初始化的bean對象會被傳遞進來,我們就可以對這個bean作任何處理。 這個函數(shù)會在InitialzationBean完成后執(zhí)行,因此稱為后置處理。
Spring Aware是Spring定義的回調(diào)接口。何為回調(diào)?就是客戶程序C調(diào)用服務(wù)程序S中的某個函數(shù)A,然后S又在某個時候反過來調(diào)用C中的某個函數(shù)B,對于C來說,這個B便叫做回調(diào)函數(shù)。
1.2.3 測試生命周期
我們自定義一個User實體類,要求Spring容器使用我們自定義的@MyAutowired注解標(biāo)注的構(gòu)造方法進行構(gòu)造Bean對象,然后我們觀察在Bean周期的日志打印,更好的理解Bean周期過程。
自定義@MyAutowired注解
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.CONSTRUCTOR)
public @interface MyAutowired {
}
定義User實體類
public class User implements InitializingBean, DisposableBean {
String username;
//Spring為了降低對客戶代碼的侵入性,給bean的配置提供了init-method屬性,
// 該屬性指定了在這一階段需要執(zhí)行的函數(shù)名。Spring便會在初始化階段執(zhí)行我們設(shè)置的函數(shù)。
// init-method本質(zhì)上仍然使用了InitializingBean接口。
public void init(){
System.out.println(this.getClass().getSimpleName()+" 執(zhí)行自定義初始化方法");
}
public User() {
}
@MyAutowired
public User(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
'}';
}
@Override
public void destroy() throws Exception {
System.out.println("調(diào)用DisposableBean接口的destroy方法");
}
//afterPropertiesSet()這一階段也可以在bean正式構(gòu)造完成前增加我們自定義的邏輯,
// 但它與前置處理不同,由于該函數(shù)并不會把當(dāng)前bean對象傳進來,因此在這一步?jīng)]辦法處理對象本身,
// 只能增加一些額外的邏輯。 若要使用它,我們需要讓bean實現(xiàn)該接口,把要增加的邏輯寫在該函數(shù)中。
// 然后Spring會在前置處理完成后檢測當(dāng)前bean是否實現(xiàn)了該接口,并執(zhí)行afterPropertiesSet函數(shù)
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("調(diào)用afterPropertiesSet方法");
}
}
測試代碼
public class MyTest {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
//InstantiationAwareBeanPostProcessor接口在Bean對象實例化前的方法
beanFactory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() {
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if(beanName.equals("user"))
System.out.println(beanName+" Bean對象在實例化之前操作**");
return null;
}
});
//InstantiationAwareBeanPostProcessor接口在Bean對象實例化后的方法
beanFactory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() {
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if(beanName.equals("user"))
System.out.println(beanName+" Bean對象在實例化之后操作**");
return false;
}
});
//使用自己自定義含有@MyAutowired注解的構(gòu)造方法,實例化Bean對象
beanFactory.addBeanPostProcessor(new SmartInstantiationAwareBeanPostProcessor() {
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
if(beanName.equals("user"))
System.out.println("實例化Bean對象");
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
List<Constructor<?>> collect = Arrays.stream(declaredConstructors).filter(i -> i.isAnnotationPresent(MyAutowired.class)).collect(Collectors.toList());
Constructor[] constructors = collect.toArray(new Constructor[collect.size()]);
return constructors.length>0?constructors:null;
}
});
//BeanPostProcessor接口在Bean對象初始化之前的方法調(diào)用
beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("user"))
System.out.println(beanName+" Bean對象在初始化之前操作**");
return null;
}
});
//BeanPostProcessor接口在Bean對象初始化之后的方法調(diào)用
beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("user"))
System.out.println(beanName+" Bean對象在初始化之后操作**");
return null;
}
});
RootBeanDefinition rootBeanDefinition= (RootBeanDefinition) BeanDefinitionBuilder.rootBeanDefinition(User.class).setInitMethodName("init").getBeanDefinition();
beanFactory.registerBeanDefinition("user",rootBeanDefinition);
beanFactory.registerBeanDefinition("username", BeanDefinitionBuilder.genericBeanDefinition(String.class)
.addConstructorArgValue("admin").getBeanDefinition());
System.out.println(beanFactory.getBean("user",User.class));
beanFactory.destroySingletons();
}
}
測試截圖
至此這篇文章到此結(jié)束。
?
?
到了這里,關(guān)于Spring Bean的生命周期解讀的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!