spring常见扩展接口

98 阅读6分钟

spring的启动流程中提供了如下扩展接口

  1. BeanFactoryPostProcessor
  2. BeanPostProcessor
  3. ApplicationListener

bean的创建过程中提供了如下扩展接口

  1. Aware相关接口
    1. ApplicationContextAware
    2. BeanFactoryAware
    3. ApplicationEventPublisherAware
    4. BeanNameAware
    5. EnviromentAware
  2. InitializingBean
  3. @PostContruct标记的方法
  4. SmartInitializingSingleton
  5. @Predestroy标记的方法
  6. DisposableBean

BeanFactoryPostProcessor

接口定义

BeanFactory的后置处理器,接口定义如下:
public interface BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean factory after its standard
	 * initialization. All bean definitions will have been loaded, but no beans
	 * will have been instantiated yet. This allows for overriding or adding
	 * properties even to eager-initializing beans.
	 * @param beanFactory the bean factory used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

执行时机

应用上下文内部的BeanFactory初始化完成,BeanDefinition加载完成,但还未开始创建bean。

使用场景

在BeanFactory加载bean之前,对BeanFactory做自定义修改:
  1. 加载自定义BeanDefinition。
  2. 加载自定义BeanPostProcessor.
  3. 创建前置bean。

BeanPostProcessor

接口定义

Bean的后置处理器,接口定义如下:
public interface BeanPostProcessor {

	/**
	 * Apply this {@code BeanPostProcessor} to the given new bean instance <i>before</i> any bean
	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
	 * or a custom init-method). The bean will already be populated with property values.
	 * The returned bean instance may be a wrapper around the original.
	 * <p>The default implementation returns the given {@code bean} as-is.
	 * @param bean the new bean instance
	 * @param beanName the name of the bean
	 * @return the bean instance to use, either the original or a wrapped one;
	 * if {@code null}, no subsequent BeanPostProcessors will be invoked
	 * @throws org.springframework.beans.BeansException in case of errors
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
	 */
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	/**
	 * Apply this {@code BeanPostProcessor} to the given new bean instance <i>after</i> any bean
	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
	 * or a custom init-method). The bean will already be populated with property values.
	 * The returned bean instance may be a wrapper around the original.
	 * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
	 * instance and the objects created by the FactoryBean (as of Spring 2.0). The
	 * post-processor can decide whether to apply to either the FactoryBean or created
	 * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
	 * <p>This callback will also be invoked after a short-circuiting triggered by a
	 * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
	 * in contrast to all other {@code BeanPostProcessor} callbacks.
	 * <p>The default implementation returns the given {@code bean} as-is.
	 * @param bean the new bean instance
	 * @param beanName the name of the bean
	 * @return the bean instance to use, either the original or a wrapped one;
	 * if {@code null}, no subsequent BeanPostProcessors will be invoked
	 * @throws org.springframework.beans.BeansException in case of errors
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
	 * @see org.springframework.beans.factory.FactoryBean
	 */
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

执行时机

在bean的创建过程中,已经创建bean实例,已完成依赖注入,已执行Aware相关接口。BeanPostProcessor提供的两个方法会在bean的初始化(@PostConstruct标注的初始化方法 or 实现了InitializingBean#afterPropertiesSet)前后执行。

注意:所有的bean在创建过程中都会执行BeanPostProcessor提供的两个方法。

使用场景

针对一类特定的bean做特殊处理,比如:
  1. ApplicationListenerDetector会针对实现了ApplicationListener的bean做特殊处理,将它们作为监听器加载在BeanFactory中。
  2. spring aop就是通过引入AnnotationAwareAspectJAutoProxyCreator,对原来的bean做特殊处理,将原来的bean替换成动态代理生成的bean。

ApplicationListener

接口定义

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);

}

执行时机

通过ApplicationEventPublisher发布事件之后,对应监听器的onApplicationEvent()会被执行。

使用场景

用于监听系统事件或自定义事件。

Aware相关接口

这是一系列接口,常用的是ApplicationContextAware、BeanFactoryAware、ApplicationEventPublisherAware等。

接口定义

以ApplicationContextAware为例
public interface ApplicationContextAware extends Aware {

	/**
	 * Set the ApplicationContext that this object runs in.
	 * Normally this call will be used to initialize the object.
	 * <p>Invoked after population of normal bean properties but before an init callback such
	 * as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
	 * or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
	 * {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
	 * {@link MessageSourceAware}, if applicable.
	 * @param applicationContext the ApplicationContext object to be used by this object
	 * @throws ApplicationContextException in case of context initialization errors
	 * @throws BeansException if thrown by application context methods
	 * @see org.springframework.beans.factory.BeanInitializationException
	 */
	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

执行时机

在bean的创建过程中,已经创建bean实例,已完成依赖注入。如果bean实现了Aware接口,则会执行setXXX()方法来获取特定的系统bean。

使用场景

获取系统bean并进行自定义扩展,比如: [xxl-job客户端的启动过程](https://juejin.cn/post/7445141546109173800)中,启动类XxlJobSpringExecutor就实现了ApplicationContextAware接口,目的就是获取应用上下文ApplicationContext对象,借助ApplicationContext对象读取bean中被@XxlJob标注的方法,将这些方法解析成任务处理器,并存在内存中。

InitializingBean

接口定义

public interface InitializingBean {

	/**
	 * Invoked by the containing {@code BeanFactory} after it has set all bean properties
	 * and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
	 * <p>This method allows the bean instance to perform validation of its overall
	 * configuration and final initialization when all bean properties have been set.
	 * @throws Exception in the event of misconfiguration (such as failure to set an
	 * essential property) or if initialization fails for any other reason
	 */
	void afterPropertiesSet() throws Exception;

}

执行时机

在bean的创建过程中,已经创建bean实例,已完成依赖注入,已执行Aware相关接口,BeanPostProcessor的前置方法也已执行。如果bean实现了InitializingBean,则会执行其afterPropertiesSet()。

使用场景

一般用来校验bean或者为bean做最后的初始化。

SmartInitializingSingleton

接口定义

public interface SmartInitializingSingleton {

	/**
	 * Invoked right at the end of the singleton pre-instantiation phase,
	 * with a guarantee that all regular singleton beans have been created
	 * already. {@link ListableBeanFactory#getBeansOfType} calls within
	 * this method won't trigger accidental side effects during bootstrap.
	 * <p><b>NOTE:</b> This callback won't be triggered for singleton beans
	 * lazily initialized on demand after {@link BeanFactory} bootstrap,
	 * and not for any other bean scope either. Carefully use it for beans
	 * with the intended bootstrap semantics only.
	 */
	void afterSingletonsInstantiated();

}

执行时机

所有非懒加载单例bean都已创建完成,这个时候会遍历这些单例bean,如果单例bean实现了SmartInitializingSingleton接口,则会执行其afterSingletonsInstantiated()

使用场景

在所有非懒加载单例bean创建完成之后做自定义扩展,比如:xxl-job客户端启动过程中,启动类XxlJobSpringExecutor就实现了SmartInitializingSingleton,等所有非懒加载单例bean都创建完成之后,会遍历所有单例bean并获取其中被@XxlJob标注的方法,将Method对象封装成IJobHandler对象存在内存中。

DisposableBean

接口定义

public interface DisposableBean {

	/**
	 * Invoked by the containing {@code BeanFactory} on destruction of a bean.
	 * @throws Exception in case of shutdown errors. Exceptions will get logged
	 * but not rethrown to allow other beans to release their resources as well.
	 */
	void destroy() throws Exception;

}

执行时机

销毁bean时执行

使用场景

需要进行额外的销毁工作,还是以xxl-job的客户端为例,在客户端启动过程中会启动内置服务器,用来和xxl-job服务端通信,因此在xxl-job客户端关闭时,需要先把内置服务器关闭。

XxlJobSpringExecutor源码

public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationContextAware, SmartInitializingSingleton, DisposableBean {
    private static final Logger logger = LoggerFactory.getLogger(XxlJobSpringExecutor.class);


    // start
    @Override
    public void afterSingletonsInstantiated() {

        // init JobHandler Repository
        /*initJobHandlerRepository(applicationContext);*/

        // init JobHandler Repository (for method)
        initJobHandlerMethodRepository(applicationContext);

        // refresh GlueFactory
        GlueFactory.refreshInstance(1);

        // super start
        try {
            super.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // destroy
    @Override
    public void destroy() {
        super.destroy();
    }

    private void initJobHandlerMethodRepository(ApplicationContext applicationContext) {
        if (applicationContext == null) {
            return;
        }
        // init job handler from method
        String[] beanDefinitionNames = applicationContext.getBeanNamesForType(Object.class, false, true);
        for (String beanDefinitionName : beanDefinitionNames) {

            // get bean
            Object bean = null;
            Lazy onBean = applicationContext.findAnnotationOnBean(beanDefinitionName, Lazy.class);
            if (onBean!=null){
                logger.debug("xxl-job annotation scan, skip @Lazy Bean:{}", beanDefinitionName);
                continue;
            }else {
                bean = applicationContext.getBean(beanDefinitionName);
            }

            // filter method
            Map<Method, XxlJob> annotatedMethods = null;   // referred to :org.springframework.context.event.EventListenerMethodProcessor.processBean
            try {
                annotatedMethods = MethodIntrospector.selectMethods(bean.getClass(),
                        new MethodIntrospector.MetadataLookup<XxlJob>() {
                            @Override
                            public XxlJob inspect(Method method) {
                                return AnnotatedElementUtils.findMergedAnnotation(method, XxlJob.class);
                            }
                        });
            } catch (Throwable ex) {
                logger.error("xxl-job method-jobhandler resolve error for bean[" + beanDefinitionName + "].", ex);
            }
            if (annotatedMethods==null || annotatedMethods.isEmpty()) {
                continue;
            }

            // generate and regist method job handler
            for (Map.Entry<Method, XxlJob> methodXxlJobEntry : annotatedMethods.entrySet()) {
                Method executeMethod = methodXxlJobEntry.getKey();
                XxlJob xxlJob = methodXxlJobEntry.getValue();
                // regist
                registJobHandler(xxlJob, bean, executeMethod);
            }

        }
    }

    // ---------------------- applicationContext ----------------------
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        XxlJobSpringExecutor.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

}