BeanPostProcessor 接口

218 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情

BeanPostProcessor 接口

package org.springframework.beans.factory.config;
import org.springframework.beans.BeansException;
import org.springframework.lang.Nullable;

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 后置处理器的作用

BeanPostProcessor后置处理器作用后置处理器用于bean对象初始化前后进行逻辑增强。spring提供了BeanPostProcessor的很多实现类,例如AutowiredAnnotationBeanPostProcessor用于@Autowired注解的实现,AnnotationAwareAspectJAutoProxyCreator用于SpringAOP的动态代理等等。

除此之外,我们还可以自定义BeanPostProcessor的实现类,在其中写入需要的逻辑。

下面以AnnotationAwareAspectJAutoProxyCreator为例,说明后置处理器是怎样工作的?

我们都知道springAOP的实现原理是动态代理,最终放入容器的是代理类的对象,而不是bean本身的对象,那么spring是什么时候做到这一步的?就是在AnnotationAwareAspectJAutoProxyCreator后置处理器的postProcessAfterInitialization方法,即bean对象初始化完成之后,后置处理器会判断该bean是否注册了切面,如果是,则生成代理对象注入容器。Spring中的关键代码如下所示。

如果我们想在Spring容器中完成bean实例化、配置以及其他初始化方法前后要添加一些自己逻辑处理。我们需要定义一个或多个BeanPostProcessor接口实现类,然后注册到Spring IoC容器中。

  • BeanFactoryPostProcessor 注册一个BeanFactoryPostProcessor实例需要定义一个Java类来实现BeanFactoryPostProcessor接口,并重写该接口的postProcessorBeanFactory方法。通过beanFactory可以获取bean的定义信息,并可以修改bean的定义信息。这点是和BeanPostProcessor最大区别

在这里插入图片描述 Spring内置了一些很有用的BeanPostProcessor接口实现类。比如有AutowiredAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、EventListenerMethodProcessor等。这些Processor会处理各自的场景。

ApplicationContextAwareProcessor

Spring容器的 refresh 方法内部调用prepareBeanFactory方法,prepareBeanFactory方法会添加ApplicationContextAwareProcessor到BeanFactory中。这个Processor的作用在于为实现*Aware接口的bean调用该Aware接口定义的方法,并传入对应的参数。比如实现EnvironmentAware接口的bean在该Processor内部会调用EnvironmentAware接口的setEnvironment方法,并把Spring容器内部的ConfigurableEnvironment传递进去。

CommonAnnotationBeanPostProcessor

在AnnotationConfigUtils类的registerAnnotationConfigProcessors方法中被封装成RootBeanDefinition并注册到Spring容器中。registerAnnotationConfigProcessors方法在一些比如扫描类的场景下注册。比如 context:component-scan 标签或 context:annotation-config 标签的使用,或ClassPathBeanDefinitionScanner扫描器的使用、AnnotatedBeanDefinitionReader读取器的使用。

主要处理@Resource、@PostConstruct和@PreDestroy注解的实现。

在postProcessPropertyValues过程中,该processor会找出bean中被@Resource注解修饰的属性(Field)和方法(Method),找出以后注入到bean中。

CommonAnnotationBeanPostProcessor.class
- AbstractBeanFactory#doGetBean
- AbstractAutowireCapableBeanFactory#createBean
- AbstractAutowireCapableBeanFactory#populateBean
- CommonAnnotationBeanPostProcessor#postProcessPropertyValues

	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
		//// 找出bean中被@Resource注解修饰的属性(Field)和方法(Method)
		InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
		try {
		// 注入到 bean 中
			metadata.inject(bean, beanName, pvs);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
		}
		return pvs;
	}

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }
        }
    }

Spring 是如何处理相同 beanID 的

在同一个配置文件中,不能存在id相同的两个bean,否则会报错。

但是在两个不同的spring配置文件中,可以存在id相同的两个bean,启动时,不会报错。这是因为spring ioc容器在加载bean的过程中,类DefaultListableBeanFactory会对id相同的bean进行处理:后加载的配置文件的 bean,覆盖先加载的配置文件的bean。DefaultListableBeanFactory类中,有个属性 allowBeanDefinitionOverriding,默认值为true,该值就是用来指定出现两个bean的id相同的情况下,如何进行处理。 如果该值为false,则不会进行覆盖,而是抛出异常。