如何在Spring框架上做开发之Context启动中的“Hook”
1.概述
有些时候,我们需要在spring启动过程中加入一些自己的逻辑,特别是一些基本框架和spring做整合的时候(例如:mybatis-spring-boot-starter),就需要使用Spring给我们预留的扩展接口。本文将介绍3个常用的初始化扩展接口:
2.spring初始化
下图是spring启动中,初始化ApplicationContext的3个基本步骤
Spring在初始化每个阶段都提供了一些“Hook”,提供给开发者进行扩展(开闭原则)
3.Hook
3.1 BeanFactoryPostProcessor
1 2 3 | public interface BeanFactoryPostProcessor { void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; } |
在ApplicationContext中BeanFactory所有的Bean 的定义已经加载完成,但还未实例化,这个时候可以使用该接口对Bean的属性进行覆盖和设置。
简单的例子:修改Bean的属性
1 2 3 4 5 6 7 8 9 | @Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { BeanDefinition myService = beanFactory.getBeanDefinition( "myService" ); myService.getPropertyValues().add( "name" , "Lizo" ); } } |
使用方法:
在BeanFactory中新增(或修改既有的)BeanDefinition,例如
mockito创建mockBean
3.2 BeanPostProcessor
1 2 3 4 | public interface BeanPostProcessor { Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; } |
该接口的作用是在Bean创建对象以后,在bean初始化前后提供回调方法,做一些定制化处理(例如包装成代理对象,bean对象注解处理)。
spring中大量存在BeanPostProcessor的实现类,来完成特定逻辑,下面只是一个简单的例子
简单例子:对@Service注解的Bean,打印当前BeanName
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @Component public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { Service annotation = AnnotationUtils.findAnnotation(bean.getClass(), Service. class ); if (annotation != null ) { System.out.println(beanName); } return bean; } } |
使用方法:
1.Dubbo中远程调用代理类
2.@PostConstruct注解处理
和InitializingBean,@PostConstruct,XxxAware的执行顺序
XxxAware 类似ApplicationContextAware
3.3 ApplicationListener
1 2 3 | public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { void onApplicationEvent(E event); } |
如果是BeanPostProcessor是在Bean初始化前后提供回调,那ApplicationListener就是在ApplicationContext的启动不同阶段提供回调。
根据监听的事件ApplicationEvent来完成回调。常用的事件:
其中可能用的最多的就是ContextRefreshedEvent这个时间。例如有些逻辑要放在整个ApplicationContext完全初始完成之后再执行。
简单例子:ApplicationContext初始完后,把所有BeanPostProcessor实现类设置为null
1 2 3 4 5 6 7 8 9 10 11 | @Component public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { ApplicationContext applicationContext = event.getApplicationContext(); Map<String, BeanPostProcessor> beansOfType = applicationContext.getBeansOfType(BeanPostProcessor. class ); beansOfType.forEach((k,v)->{ v = null ; }); } } |
4.小结
以上3个是Spring中对Bean进行扩展的常用接口,可以通过这些接口新增,修改,代理,校验等逻辑在spring初始化过程中运行。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步