当前位置:主页 > java教程 > Spring BeanPostProcessor

Spring BeanPostProcessor源码示例解析

发布:2023-03-10 13:00:01 59


为找教程的网友们整理了相关的编程文章,网友阙念桃根据主题投稿了本篇教程内容,涉及到Spring BeanPostProcessor、Spring源码解析、Spring BeanPostProcessor相关内容,已被962网友关注,涉猎到的知识点内容可以在下方电子书获得。

Spring BeanPostProcessor

正文

BeanPostProcessor对于Spring开发者来说一定不陌生,平时开发过程中如果涉及对中间件做增强处理或者需要对某个实际Bean做初始化前的处理,一般都可以使用该接口来实现。

对于自己来说自己在对接RocketMQ、RabbitMQ过程中需要实现一个快速接入SpringBoot的中间插件,最快速的就是实现该接口对中间件中的Bean做增强处理,能够快速接入SpringBoot。

1. BeanPostProcessor介绍

BeanPostProcessor是一个接口,该接口提供给开发者使用,开发者可以实现该接口,然后在实现类中对想要处理的类做增强处理。

该接口中提供了两个基础方法:

  • postProcessBeforeInitialization:Bean初始化前对Bean的增强处理
  • postProcessAfterInitialization:Bean初始化后对Bean的增强处理
public interface BeanPostProcessor {
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

下面举一个最简单的例子来看一下BeanPostProcessor的使用。

2. BeanPostProcessor的使用

@Service
public class UserService {
    private String name = "陈tom";
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
@Component
public class MyPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("userService".equals(beanName)) {
            UserService userService = (UserService) bean;
            userService.setName("陈汤姆");
            userService.setAge(21);
        }
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}
@SpringBootApplication
public class BootApplication {
    @Resource
    private DefaultListableBeanFactory defaultListableBeanFactory;
    public static void main(String[] args) {
        SpringApplication.run(BootApplication.class,args);
    }
    @PostConstruct
    public void init() {
        UserService userService = defaultListableBeanFactory.getBean("userService", UserService.class);
        System.out.println("测试结果:姓名:"+userService.getName()+";年龄:"+userService.getAge());
    }
}

以上的实现中做了最简单的实现,通过MyPostProcessor实现BeanPostProcessor接口,然后在前置增强处理中加入对Bean的修改。

然后通过PostConstruct在Bean初始化后做Bean的查询,得到通过BeanPostProcessor操作的结果。

所以BeanPostProcessor在使用上来说很简单,对于开发者来说它很方便的提供了对于Bean对象的修改操作,提高了Spring的扩展性和灵活性。

3. BeanPostProcessor的作用

说完了最基础的BeanPostProcessor的使用,通过以上的实现来梳理下BeanPostProcessor的作用。

  • 对Bean的修改操作,通过实现该接口可以很快的实现对Bean的操作
  • 提供前置和后置两个处理,提供开发者可以在初始化前做处理以及初始化后做处理
  • 对于Spring框架的灵活性,使用Spring框架也可以很方便的做自己的逻辑处理

自己对于BeanPostProcessor最大的感受就是太灵活了,开发者只要实现该接口,然后重写其中的方法就可以实现自己的逻辑。这样也保证了Spring容器对于开发者来说并不是一个黑盒,开发者可以通过Spring提供的钥匙让Spring容器暴露在开发者眼中,想要做什么处理都可以根据提供的钥匙实现。(这里其实还有一个配套的BeanFactoryPostProcessor,面试的时候也经常被问到BeanPostProcessor和BeanFactoryPostProcessor的区别,有兴趣的可以自己了解下,区别只是最终服务的对象不一样)

这里不得不说Spring YYDS!!!

4. BeanPostProcessor注册

Q:既然开发者通过自己的实现类实现了BeanPostProcessor,那么Spring又是如何将开发者做的实现类加入到Spring中并且执行开发者重写的前置和后置增强逻辑呢?

这里就要提到Spring对于BeanPostProcessor的设计,在Spring中初始化了一个CopyOnWriteArrayList作为存储所有实现BeanPostProcessor的列表。

从实现上可以看到该列表是一个写复制的列表,通俗点讲就是向该列表中添加元素时,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这里不展开说只要知道就是一个列表就可以。

Spring向该容器中添加的逻辑源码如下:

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
	//存储BeanPostProcessor列表
	private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
	@Override
	public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
		Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
		// Remove from old position, if any
		this.beanPostProcessors.remove(beanPostProcessor);
		// Track whether it is instantiation/destruction aware
		if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
			this.hasInstantiationAwareBeanPostProcessors = true;
		}
		if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
			this.hasDestructionAwareBeanPostProcessors = true;
		}
		// 将BeanPostProcessor加入beanPostProcessors列表中
		this.beanPostProcessors.add(beanPostProcessor);
	}
}

这里展示的只是最终写入的逻辑,那么从源头到写入BeanPostProcessor的逻辑是怎么样呢?

以ClassPatchXmlApplicationContext为例:

  • org.springframework.context.support.ClassPathXmlApplicationContext#ClassPathXmlApplicationContext
  • org.springframework.context.support.AbstractApplicationContext#refresh
  • org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, org.springframework.context.support.AbstractApplicationContext)
  • org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List<org.springframework.beans.factory.config.BeanPostProcessor>)
  • org.springframework.beans.factory.support.AbstractBeanFactory#addBeanPostProcessor

时序图如下:

5. BeanPostProcessor调用

说完如何注册BeanPostProcessor,最后来说如何将注册到beanPostProcessors的实现类进行调用。

前一篇聊Spring容器时也提到了Spring在初始化Bean时会执行BeanPostProcessor的增强处理,具体的调用源码如下:

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
		implements AutowireCapableBeanFactory {
	//初始化Bean
	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}
		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//调用BeanPostProcesso#postProcessBeforeInitialization:前置处理
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}
		try {
			//执行初始化方法
			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()) {
			//调用调用BeanPostProcesso#postProcessAfterInitialization:后置处理
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
		return wrappedBean;
	}
	//BeanPostProcessor前置逻辑处理
	@Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {
		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			//执行实现BeanPostProcessor的实现类的前置增强逻辑
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}
	//BeanPostProcessor后置逻辑处理
	@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {
		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			//执行实现BeanPostProcessor的实现类的后置增强逻辑
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}
}

从以上源码中可以看到在初始化Bean时调用前置和后置增强,并且这里也做了明确的边界,前置增强处理一定是在invokeInitMethods之前,后置增强一定是在invokeInitMethods之后。这样就保证了BeanPostProcessor的执行顺序,也可以让开发者在使用过程中只要掌握Bean的生命周期,那么就可以自主的对Bean进行增强处理。

6. 总结

以上是对Spring中BeanPostProcessor的源码梳理,对BeanPostProcessor的介绍到使用、作用、注册实现和调用实现,完成了对BeanPostProcessor的源码分析。

对于文中提到的BeanFactoryPostProcessor有兴趣的可以从源码按照这个过程梳理一下,其实跟BeanPostProcessor作用是相同的。

以上就是Spring BeanPostProcessor源码示例解析的详细内容,更多关于Spring BeanPostProcessor的资料请关注码农之家其它相关文章!


参考资料

相关文章

  • Spring中Bean注入源码示例解析

    发布:2023-03-10

    这篇文章主要为大家介绍了Spring中Bean注入源码示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪


网友讨论