javascript
Spring重写BeanDefinitionRegistryPostProcessors进行扩展
文章目錄
- 1. 前言
- 2. BeanDefinitionRegistryPostProcessors 作用
- 3. 代碼示例
- 4. 底層實(shí)現(xiàn)解析
- 5. 總結(jié)
1. 前言
最近項(xiàng)目中遇到這么個(gè)問題,公司底層封裝的框架有UserService(接口)和 UserServiceImpl(實(shí)現(xiàn)類)。基于此框架開發(fā)的項(xiàng)目,通過如下代碼就能直接從Spring容器取出 UserServiceImpl 對(duì)象:
@Autowired private UserService userService;現(xiàn)在有個(gè)項(xiàng)目A,UserService.save方法不滿足項(xiàng)目需求。因此在項(xiàng)目中重寫save方法,并且不能修改框架代碼。思來想去,實(shí)現(xiàn)的方法可能有多種,但是都比較麻煩。最理想的方案是創(chuàng)建 MyUserServiceImpl 繼承 UserServiceImpl,并重寫相關(guān)方法,例如:
public class MyUserServiceImpl: UserServiceImpl {public void onBeforeSave(User user){//各個(gè)項(xiàng)目在這里重寫特殊邏輯}public void onAfterSave(User user){//各個(gè)項(xiàng)目在這里重寫特殊邏輯} }思路有了,那還有最后一個(gè)問題需要解決:屬性注入 UserService userService 取到的對(duì)象是 UserServiceImpl ,怎么自動(dòng)替換成新增的 MyUserServiceImpl?
為了解決這個(gè)問題,就需要用到Spring提供的后置處理器 PostProcessor 。
2. BeanDefinitionRegistryPostProcessors 作用
先看這張圖,大致介紹了 Spring 容器初始化的過程:
如果說 Class 是Java對(duì)象的元數(shù)據(jù)信息,那么 BeanDefinition 就是 Spring Bean 的描述信息。
BeanDefinition 記錄了 Spring Bean 的一些重要字段,例如:scope作用域、lazyInit是否懶加載、dependsOn、beanClassName類名等等
如圖所示,黃色節(jié)點(diǎn)的第3點(diǎn),掃描類的最后一步會(huì)執(zhí)行程序員創(chuàng)建的 BeanDefinitionRegistryPostProcessor 對(duì)象。
因此,我們?cè)谶@一步取出 UserServiceImpl 對(duì)應(yīng)的BeanDefinition,然后將其 BeanClassName 改成 MyUserServiceImpl.class 。最終,在創(chuàng)建Bean的時(shí)候就不再創(chuàng)建UserServiceImpl,而是MyUserServiceImpl。
3. 代碼示例
創(chuàng)建接口類 UserService :
public interface UserService {void save(); }創(chuàng)建實(shí)現(xiàn)類 UserServiceImpl :
@Service public class UserServiceImpl implements UserService {@Overridepublic void save() {onBeforeSave();System.out.println("執(zhí)行Save方法");onAfterSave();}public void onBeforeSave(){System.out.println("UserServiceImpl.onBeforeSave");}public void onAfterSave(){System.out.println("UserServiceImpl.onAfterSave");} }創(chuàng)建應(yīng)用程序啟動(dòng)類:
@ComponentScan("com.train") public class SpringAnnotationApp {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringAnnotationApp.class);UserService userService = applicationContext.getBean(UserService.class);System.out.println(userService.getClass());userService.save();} }因?yàn)槲覀冞€沒做任何處理,所以默認(rèn)情況創(chuàng)建的是 UserServiceImpl 對(duì)象,輸出結(jié)果如下
class com.train.service.impl.UserServiceImpl UserServiceImpl.onBeforeSave 執(zhí)行Save方法 UserServiceImpl.onAfterSave重點(diǎn)來了,創(chuàng)建 MyBeanDefinitionRegistryPostProcessor 實(shí)現(xiàn) BeanDefinitionRegistryPostProcessor 接口
@Component public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {BeanDefinition beanDefinition = registry.getBeanDefinition("userServiceImpl");beanDefinition.setBeanClassName(MyUserServiceImpl.class.getName());}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {} }其他代碼不動(dòng),重新運(yùn)行程序,結(jié)果變了,達(dá)到了我們的要求:
class com.train.inherit.MyUserServiceImpl MyUserServiceImpl.onBeforeSave 執(zhí)行Save方法 MyUserServiceImpl.onAfterSave4. 底層實(shí)現(xiàn)解析
上面講了應(yīng)用場(chǎng)景,接下來介紹Spring源碼如何實(shí)現(xiàn)的。
跳過無關(guān)的代碼,直接查看 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors,以下是核心代碼和相關(guān)注釋。主要貼出的是 BeanDefinitionRegistryPostProcessors 部分。
這個(gè)類的代碼比較多,還有一部分是 BeanFactoryPostProcessors, 這里先刪掉了
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {Set<String> processedBeans = new HashSet<>();if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();/*** 1.從Spring容器獲取實(shí)現(xiàn) BeanDefinitionRegistryPostProcessor 接口的處理器* 2.到這里為止,我們自己寫的Bean還沒加載到容器,因此,可以理解為此處執(zhí)行的是Spring自帶的 BeanDefinitionRegistryPostProcessor(實(shí)現(xiàn)類是ConfigurationClassPostProcessor)* 3.ConfigurationClassPostProcessor作用是掃描程序員定義的,需要給Spring管理的類,并封裝成BeanDefinition*/String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();/*** 1.再次從Spring容器獲取實(shí)現(xiàn) BeanDefinitionRegistryPostProcessor 接口的處理器* 2.排除掉上一步執(zhí)行過的PostProcessor,剩余的就是程序員定義的PostProcessor* 3.判斷是否實(shí)現(xiàn) Ordered 排序接口,沒有實(shí)現(xiàn)就先跳過(保證程序員指定的按順序執(zhí)行)* 4.執(zhí)行程序員寫的BeanDefinitionRegistryPostProcessor方法*/postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();/*** 1.再次從Spring容器獲取實(shí)現(xiàn) BeanDefinitionRegistryPostProcessor 接口的處理器* 2.過濾掉前面2步執(zhí)行過的PostProcessor,剩余的就是程序員定義的,并且沒有實(shí)現(xiàn) Ordered 排序接口的部分* 3.執(zhí)行程序員寫的BeanDefinitionRegistryPostProcessor方法*/boolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();}}}5. 總結(jié)
- 上面的代碼只是舉個(gè)例子,如果重寫類較多的話,一個(gè)個(gè)修改比較麻煩。如果運(yùn)用到實(shí)際項(xiàng)目中,可以采取約定的規(guī)則掃描類,然后自動(dòng)遍歷處理BeanDefinition。
- Spring 提供的 PostProcessor 目的就是允許程序員對(duì)其進(jìn)行擴(kuò)展,本文講解的 BeanDefinitionRegistryPostProcessor 到這里就結(jié)束了,后面的其他文章將會(huì)陸續(xù)介紹其他擴(kuò)展點(diǎn)。
總結(jié)
以上是生活随笔為你收集整理的Spring重写BeanDefinitionRegistryPostProcessors进行扩展的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java源码解析:ArrayList 和
- 下一篇: Spring扫描类过程解析和案例