spring的启动流程中提供了如下扩展接口
- BeanFactoryPostProcessor
- BeanPostProcessor
- ApplicationListener
bean的创建过程中提供了如下扩展接口
- Aware相关接口
- ApplicationContextAware
- BeanFactoryAware
- ApplicationEventPublisherAware
- BeanNameAware
- EnviromentAware
- InitializingBean
- @PostContruct标记的方法
- SmartInitializingSingleton
- @Predestroy标记的方法
- 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做自定义修改:- 加载自定义BeanDefinition。
- 加载自定义BeanPostProcessor.
- 创建前置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做特殊处理,比如:- ApplicationListenerDetector会针对实现了ApplicationListener的bean做特殊处理,将它们作为监听器加载在BeanFactory中。
- 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;
}
}