如何在Spring框架上做开发之Context启动中的“Hook”
1.概述
有些时候,我们需要在spring启动过程中加入一些自己的逻辑,特别是一些基本框架和spring做整合的时候(例如:mybatis-spring-boot-starter),就需要使用Spring给我们预留的扩展接口。本文将介绍3个常用的初始化扩展接口:
2.spring初始化
下图是spring启动中,初始化ApplicationContext的3个基本步骤
Spring在初始化每个阶段都提供了一些“Hook”,提供给开发者进行扩展(开闭原则)
3.Hook
3.1 BeanFactoryPostProcessor
public interface BeanFactoryPostProcessor { void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; }
在ApplicationContext中BeanFactory所有的Bean 的定义已经加载完成,但还未实例化,这个时候可以使用该接口对Bean的属性进行覆盖和设置。
简单的例子:修改Bean的属性
@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
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
@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
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { void onApplicationEvent(E event); }
如果是BeanPostProcessor是在Bean初始化前后提供回调,那ApplicationListener就是在ApplicationContext的启动不同阶段提供回调。
根据监听的事件ApplicationEvent来完成回调。常用的事件:
其中可能用的最多的就是ContextRefreshedEvent这个时间。例如有些逻辑要放在整个ApplicationContext完全初始完成之后再执行。
简单例子:ApplicationContext初始完后,把所有BeanPostProcessor实现类设置为null
@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初始化过程中运行。