Spring BeanPostProsser最佳实践
2021-11-10 本文已影响0人
liaijuyyer
BeanPostProcessor接口的作用是在Spring bean 实例化完成后(执行完initializeBean)之后,初始化之前(执行bean的初始化方法)对Bean添加一些自定义的处理逻辑。也就是说执行beanProcessor方法是在bean实例化之后 此时bean的属性值都已经被赋值好了。另外需要注意的是 beanProcessor的实现类一定要被Spring托管才能生效。
一、BeanPostProcessor示例
-
实体类
@Component @ConfigurationProperties(prefix = "spring.datasource") public class DataSourceProperty { private String userName; private String password; /** * 通过@PostConstruct来标记这个init方法为bean的初始化方法 **/ @PostConstruct private void init() { //这条语句会在 beanprocessor的postProcessBeforeInitialization方法执行之后执行 2 System.out.println("执行初始化方法"); } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
-
配置
spring.datasource.username=test spring.datasource.password=12345678
-
自定义的BeanPostProcessor实现类
//这个类一定要被spring容器托管(也就是要能够被spring识别为一个bean) postProcessBeforeInitialization 和 //postProcessAfterInitialization才会生效 @Component public class MyBeanPostProcessor implements BeanPostProcessor { /** * bean实例化前处理 * @param bean * @param beanName * @return * @throws BeansException */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof DataSourceProperty) { //这条语句是最先打印的 1 DataSourceProperty 此时它的两个属性是已经被赋值了的 System.out.println("dataSourceProperty 初始化前执行 dataSourceProperty" ); } return bean; } /** * bean实例化后处理 * @param bean * @param beanName * @return * @throws BeansException */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof DataSourceProperty) { //这条语句是最后打印的 System.out.println("dataSourceProperty 初始后执行" ); } return bean; } }
-
结果
二、为什么BeanPostProcessor必须被Spring托管才能生效
关于这一点可以查看源码
-
第一步
当Spring容器启动时 会先执行AbstractApplicationContext类的refresh方法 通过该方法去初始化我们的Spring容器 源码如下public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //省略前面若干方法 prepareBeanFactory(beanFactory); try { //此处省略若干方法 // 向Spring容器注册beanProstProcessor registerBeanPostProcessors(beanFactory); beanPostProcess.end(); //此处省略若干方法 完成Spring容器刷新工作 finishRefresh(); }catch (BeansException ex) { //此处省略 }finally { //此处生路 } } } }
-
第二步
从第一步 我们知道了当Spring容器在执行refresh方法的时候 会向容器中注册beanProcessor 下面接着看registerBeanPostProcessors(beanFactory)方法的逻辑 该方法的真正实现是在PostProcessorRegistrationDelegate类中final class PostProcessorRegistrationDelegate { public static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { //核心方法 从beanFactory中获取容器中所有实现了BeanPostProcessor接口的bean的名称 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); //此后省略若干方法 } }
-
第三步
beanFactory.getBeanNamesForType() 这个方法真正的实现是在DefaultListableBeanFactory中public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { @Override public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) { if (!isConfigurationFrozen() || type == null || !allowEagerInit) { //真正获取beanPostProcessor的名称的方法 return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit); } //此处省略若干方法 return resolvedBeanNames; } }
-
第四步
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) { List<String> result = new ArrayList<>(); // 它会遍历Spring容器的beanDefinitionNames for (String beanName : this.beanDefinitionNames) { //此处省略若干方法 //如果类型是指定的类型 则将这个bean的名称加入到list中 //对于BeanPostProcessor来说 此时type就是BeanPostProcessor boolean matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit); //此处省略若干方法 if (matchFound) { result.add(beanName); } //此处省略若干方法 } return StringUtils.toStringArray(result); } }
可以发现它最终还是需要通过遍历Spring容器中所有的beanName才能够将这个bean注册为BeanProcessor 如果这个BeanPostProcessor的实现类都没有被Spring托管 也就不可能被注册为beanProcessor 这也就是为什么beanProcessor的实现类必须被spring托管才能生效。
三、BeanPostProcessor执行的流程
//第一步 容器刷新
1、AbstractApplicationContext.refresh()
//第二步 完成beanFactory初始化
2、AbstractApplicationContext.finishBeanFactoryInitialization(beanFactory);
//第三步 默认的beanFactory开始预实例化单例bean
3、DefaultListableBeanFactory.preInstantiateSingletons();
//第四步 开始根据bean的名称获取bean
4、AbstractBeanFactory.getBean(String name);
//第五步 执行doCreateBean方法 开始创建bean
5、AbstractAutowireCapableBeanFactory.doCreateBean()
//第六步 对bean进行初始化
AbstractAutowireCapableBeanFactory.initializeBean()
//第七步 开始遍历beanProcessor 执行beanProcessor的postProcessBeforeInitialization方法
AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization();
//第八步 执行beanPostProcessor的后置方法
AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization();
initializeBean源码
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
//此处省略若干方法
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//执行beanPostProcessor的前置方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//执行bean的初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//执行beanPostProcessor的后置方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
applyBeanPostProcessorsBeforeInitialization源码
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
//遍历beanPostProcessor 执行前置方法
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
applyBeanPostProcessorsAfterInitialization源码
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}