o2o網(wǎng)站建設(shè)最好公司排名搜索關(guān)鍵詞技巧
目錄
- 前言
- Spring的后置處理器
- Bean工廠后置處理器
- Bean后置處理器
- 自定義@Component實(shí)現(xiàn)注解開發(fā)
前言
看這篇文章之前,需要了解Bean創(chuàng)建的過程,本篇文章是接著bean創(chuàng)建的基本流程的續(xù)寫
Bean創(chuàng)建的基本過程:http://t.csdn.cn/1lK2d
Spring的后置處理器
(熟悉Bean創(chuàng)建的基本流程是前提)
Spring的后處理器是Spring對(duì)外開發(fā)的重要擴(kuò)展點(diǎn),允許我們介入到Bean的整個(gè)實(shí)例化流程中來,以達(dá)到動(dòng)態(tài)注冊(cè)BeanDefinition,動(dòng)態(tài)修改BeanDefinition,以及動(dòng)態(tài)修改Bean的作用。Spring主要有兩種后處理器:
- BeanFactoryPostProcessor:Bean工廠后處理器,在BeanDefinitionMap填充完畢,Bean實(shí)例化之前執(zhí)行;
- BeanPostProcessor:Bean后處理器,一般在Bean實(shí)例化之后,填充到單例池singletonObjects之前執(zhí)行
那Spring的后置處理器有什么用處呢?
不知道你看到它可以動(dòng)態(tài)注冊(cè)BeanDefinition時(shí)有什么想法,對(duì),你想的沒錯(cuò),注解開發(fā)原理中就是用Spring的后置處理器來動(dòng)態(tài)創(chuàng)建Bean對(duì)象的,別眨眼,接下來就時(shí)見證奇跡的時(shí)刻
Bean工廠后置處理器
Bean工廠后處理器,在BeanDefinitionMap填充完畢,Bean實(shí)例化之前執(zhí)行;也就是當(dāng)把xml中所有bean配置信息封裝成BeanDefinition對(duì)象,裝到BeanDefinitionMap集合后,但還沒有反射創(chuàng)建bean對(duì)象時(shí),再往map中注冊(cè)BeanDefinition對(duì)象,后續(xù)反射就會(huì)創(chuàng)建出新的xml中未定義的對(duì)象
Bean工廠后處理器 – BeanFactoryPostProcessor
BeanFactoryPostProcessor是一個(gè)接口規(guī)范,實(shí)現(xiàn)了該接口的類只要交由Spring容器管理的話,在BeanDefinitionMap填充完畢后,Spring就會(huì)回調(diào)該接口的方法,用于對(duì)BeanDefinition注冊(cè)和修改的功能。
所以它的使用分以下幾步
- 創(chuàng)建一個(gè)處理器類實(shí)現(xiàn)BeanFactoryPostProcessor接口
- 重寫B(tài)eanFactoryPostProcessor的方法
- 交給Spring容器管理(配置到xml中或加注解)
使用方式如下
由于BeanDefinition是接口,我們要new 一個(gè)BeanDefinition對(duì)象,就要new 它的一個(gè)實(shí)現(xiàn)類RootBeanDefinition對(duì)象
其中需要強(qiáng)轉(zhuǎn)為DefaultListableBeanFactory是因?yàn)?#xff0c;ConfigurableListableBeanFactory的對(duì)象無法把beanDefinition注冊(cè)到map中,BeanDefinitionMap是DefaultListableBeanFactory中定義的集合,而DefaultListableBeanFactory又是實(shí)現(xiàn)了ConfigurableListableBeanFactory的接口,所以強(qiáng)轉(zhuǎn)一下。
不得不說,這個(gè)源碼自己也需要多看,不然這些接口名類名是什么,繼承了什么,有什么關(guān)鍵成員變量都不清楚,看這些調(diào)用關(guān)系自然就云里霧里
Spring 提供了一個(gè)BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor專門用于注冊(cè)BeanDefinition操作
public class MyBeanFactoryPostProcessor2 implements BeanDefinitionRegistryPostProcessor {//這個(gè)方法是BeanFactoryPostProcessor接口的方法,重寫一下就不用管了@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {}@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {BeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName("com.dao.UserDaoImpl");//要?jiǎng)?chuàng)建的bean的位置//注冊(cè)beanDefinitionbeanDefinitionRegistry.registerBeanDefinition("userDao",beanDefinition);}
}
最后main方法中調(diào)用時(shí)
UserDao userDao = applicationContext.getBean(UserDao.class)
Bean后置處理器
Bean后處理器 – BeanPostProcessor
Bean被實(shí)例化后,到最終緩存到名為singletonObjects單例池之前,中間會(huì)經(jīng)過Bean的初始化過程,例如:屬性的填充、初始方法init的執(zhí)行等,其中有一個(gè)對(duì)外進(jìn)行擴(kuò)展的點(diǎn)BeanPostProcessor,我們稱為Bean后處理。跟上面的Bean工廠后處理器相似,它也是一個(gè)接口,實(shí)現(xiàn)了該接口并被容器管理的BeanPostProcessor,會(huì)在流程節(jié)點(diǎn)上被Spring自動(dòng)調(diào)用。
bean后處理器的使用步驟和bean工廠后處理器基本類似,只是處理時(shí)機(jī)不一樣,bean工廠后處理器在填充map后,實(shí)例化前;bean后處理器在實(shí)例化后,添加單例池前
- 創(chuàng)建后處理器類(自己隨便創(chuàng)建一個(gè)就行)
- 實(shí)現(xiàn) BeanPostProcessor接口,重寫它的方法
- 把后處理器類交由bean管理
BeanPostProcessor的接口定義如下(模板):
public interface BeanPostProcessor {@Nullable//表示該方法可以不寫//在屬性注入完畢,init初始化方法執(zhí)行之前被回調(diào)default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Nullable//在初始化方法執(zhí)行之后,被添加到單例池singletonObjects之前被回調(diào)default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}
自定義@Component實(shí)現(xiàn)注解開發(fā)
- 自定義@MyComponent注解,使用在類上;
- 使用包掃描器工具BaseClassScanUtils 完成指定包的類掃描;
- 自定義BeanFactoryPostProcessor完成注解@MyComponent的解析,解析后最終被Spring管理。(注意實(shí)現(xiàn)BeanFactoryPostProcessor接口的類需要交由Spring管理)
原理大概就是用包掃描工具類,指定包及其子包下的類上加了自定義注解的類名獲取并添加到一個(gè)map集合中,然后遍歷依次對(duì)它們進(jìn)行包裝成一個(gè)個(gè)BeanDefinition對(duì)象,然后再它們注冊(cè)到BeanDefinitionMap集合中,后續(xù)反射創(chuàng)建bean時(shí),這些注解添加的bean也會(huì)被創(chuàng)建。
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {//指定要掃描的包String basePackage = "com";//調(diào)用掃描工具BaseClassScanUtils掃描指定包及其子包下的@MyComponentMap<String, Class> myComponentClassMap = BaseClassScanUtils.scanMyComponentAnnotation(basePackage);//遍歷Map集合,創(chuàng)建BeanDefinition對(duì)象進(jìn)行注冊(cè)myComponentClassMap.forEach((beanName,clazz)->{try {BeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName(clazz.getName());registry.registerBeanDefinition(beanName,beanDefinition);} catch (Exception e) {e.printStackTrace();}});}
不得不說有那味了