1、Spring中常用的扩展点
-
org.springframework.boot.env.EnvironmentPostProcessor
-
org.springframework.context.ApplicationContextInitializer
-
org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor
-
org.springframework.beans.factory.config.BeanFactoryPostProcessor
-
org.springframework.beans.factory.BeanNameAware
-
org.springframework.context.EnvironmentAware
-
org.springframework.context.ApplicationContextAware
-
org.springframework.beans.factory.InitializingBean
-
javax.annotation.PostConstruct
-
org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
-
org.springframework.beans.factory.config.BeanPostProcessor
-
org.springframework.boot.ApplicationRunner
-
org.springframework.boot.CommandLineRunner
Spring中很非常多的扩展点,用户可以根据自己的项目按需扩展自己的方法,然后统一被Springboot管理。每一个扩展点执行的时机和作用都是不一样的。笔者这里总结了自己常用的一些扩展点。
2、EnvironmentPostProcessor
org.springframework.boot.env.EnvironmentPostProcessor
/**
* Allows for customization of the application's {@link Environment} prior to the
* application context being refreshed.
* <p>
* EnvironmentPostProcessor implementations have to be registered in
* {@code META-INF/spring.factories}, using the fully qualified name of this class as the
* key. Implementations may implement the {@link org.springframework.core.Ordered Ordered}
* interface or use an {@link org.springframework.core.annotation.Order @Order} annotation
* if they wish to be invoked in specific order.
* <p>
* Since Spring Boot 2.4, {@code EnvironmentPostProcessor} implementations may optionally
* take the following constructor parameters:
* <ul>
* <li>{@link DeferredLogFactory} - A factory that can be used to create loggers with
* output deferred until the application has been fully prepared (allowing the environment
* itself to configure logging levels).</li>
* <li>{@link Log} - A log with output deferred until the application has been fully
* prepared (allowing the environment itself to configure logging levels).</li>
* <li>{@link ConfigurableBootstrapContext} - A bootstrap context that can be used to
* store objects that may be expensive to create, or need to be shared
* ({@link BootstrapContext} or {@link BootstrapRegistry} may also be used).</li>
* </ul>
*
* @author Andy Wilkinson
* @author Stephane Nicoll
* @since 1.3.0
*/
@FunctionalInterface
public interface EnvironmentPostProcessor {
/**
* Post-process the given {@code environment}.
* @param environment the environment to post-process
* @param application the application to which the environment belongs
*/
void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application);
}
该扩展点可以获取上下文的环境以及上下文。
SpringApplication
增加一些ApplicationContextInitializer
等参数。也是项目启动时,整理的扩展点中最先执行的扩展点。注释钟也说明了,该扩展的的配置必须配置在
META-INF/spring.factories
中。如:org.springframework.boot.env.EnvironmentPostProcessor=xxx.MyEnvironmentPostProcessor
Spring 官网中也给了答案:
https://docs.spring.io/spring-boot/docs/2.5.2/reference/htmlsingle/#howto.application.customize-the-environment-or-application-context
3、ApplicationContextInitializer
org.springframework.context.ApplicationContextInitializer
/**
* Callback interface for initializing a Spring {@link ConfigurableApplicationContext}
* prior to being {@linkplain ConfigurableApplicationContext#refresh() refreshed}.
*
* <p>Typically used within web applications that require some programmatic initialization
* of the application context. For example, registering property sources or activating
* profiles against the {@linkplain ConfigurableApplicationContext#getEnvironment()
* context's environment}. See {@code ContextLoader} and {@code FrameworkServlet} support
* for declaring a "contextInitializerClasses" context-param and init-param, respectively.
*
* <p>{@code ApplicationContextInitializer} processors are encouraged to detect
* whether Spring's {@link org.springframework.core.Ordered Ordered} interface has been
* implemented or if the {@link org.springframework.core.annotation.Order @Order}
* annotation is present and to sort instances accordingly if so prior to invocation.
*
* @author Chris Beams
* @since 3.1
* @param <C> the application context type
* @see org.springframework.web.context.ContextLoader#customizeContext
* @see org.springframework.web.context.ContextLoader#CONTEXT_INITIALIZER_CLASSES_PARAM
* @see org.springframework.web.servlet.FrameworkServlet#setContextInitializerClasses
* @see org.springframework.web.servlet.FrameworkServlet#applyInitializers
*/
@FunctionalInterface
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
/**
* Initialize the given application context.
* @param applicationContext the application to configure
*/
void initialize(C applicationContext);
}
初始化上下文后的一个回调,可以直接拿到上下文。通过上下文可以获取到上文的环境
getEnvironment()
。执行的时机实在上下初始化之后,实例化Bean之前执行的。
使用场景:初始化上下文之后,对Bean属性的检查可以放在这里处理,例如IP、url是否可用等
配置:
ApplicationContextInitializer
配置有三种方式
方式一:扩展类配置
/** * * https://docs.spring.io/spring-boot/docs/2.5.2/reference/htmlsingle/#howto.application.customize-the-environment-or-application-context * * @author: ws * @date: 2025/1/16 15:07 */ public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor { @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { application.addInitializers(new MyApplicationContextInitializer()); System.out.println(">>>>>>>>>>>>>>>>MyEnvironmentPostProcessor -------------------------->"); } }
方式二:Java启动类增加参数
@SpringBootApplication public class SpringbootExtendApplication { public static void main(String[] args) { //SpringApplication.run(SpringbootExtendApplication.class, args); SpringApplication application = new SpringApplication(SpringbootExtendApplication.class); application.addInitializers(new MyApplicationContextInitializer()); application.run(args); } }
方式三:在配置文件中配置
context.initializer.classes=xx.xx.MyApplicationContextInitializer
方式四: 在
META-INF/spring.factories
【推荐】org.springframework.context.ApplicationContextInitializer=xx.xx.MyApplicationContextInitializer
4、BeanDefinitionRegistryPostProcessor
org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor
/**
* Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for
* the registration of further bean definitions <i>before</i> regular
* BeanFactoryPostProcessor detection kicks in. In particular,
* BeanDefinitionRegistryPostProcessor may register further bean definitions
* which in turn define BeanFactoryPostProcessor instances.
*
* @author Juergen Hoeller
* @since 3.0.1
* @see org.springframework.context.annotation.ConfigurationClassPostProcessor
*/
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean definition registry after its
* standard initialization. All regular bean definitions will have been loaded,
* but no beans will have been instantiated yet. This allows for adding further
* bean definitions before the next post-processing phase kicks in.
* @param registry the bean definition registry used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
从源码中可以看出
BeanDefinitionRegistryPostProcessor
继承BeanFactoryPostProcessor
,也就是BeanDefinitionRegistryPostProcessor
拥有更丰富的功能。该扩展可以通过
BeanDefinitionRegistry
获取BeanDefinition
,然后根据需要修改或者其他处理。 同时还具备BeanFactoryPostProcessor
扩展的功能。
5、BeanFactoryPostProcessor
org.springframework.beans.factory.config.BeanFactoryPostProcessor
@FunctionalInterface
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;
}
可以通过方法获取
ConfigurableListableBeanFactory
,可以用来获取任意的Bean等操作
6、BeanNameAware | EnvironmentAware | ApplicationContextAware
org.springframework.beans.factory.BeanNameAware
这三个扩展点比较简单就是对外提供BeanName、Environment和ApplicationContext
public interface BeanNameAware extends Aware {
/**
* Set the name of the bean in the bean factory that created this bean.
* <p>Invoked after population of normal bean properties but before an
* init callback such as {@link InitializingBean#afterPropertiesSet()}
* or a custom init-method.
* @param name the name of the bean in the factory.
* Note that this name is the actual bean name used in the factory, which may
* differ from the originally specified name: in particular for inner bean
* names, the actual bean name might have been made unique through appending
* "#..." suffixes. Use the {@link BeanFactoryUtils#originalBeanName(String)}
* method to extract the original bean name (without suffix), if desired.
*/
void setBeanName(String name);
}
org.springframework.context.EnvironmentAware
/**
* Interface to be implemented by any bean that wishes to be notified
* of the {@link Environment} that it runs in.
*
* @author Chris Beams
* @since 3.1
* @see org.springframework.core.env.EnvironmentCapable
*/
public interface EnvironmentAware extends Aware {
/**
* Set the {@code Environment} that this component runs in.
*/
void setEnvironment(Environment environment);
}
org.springframework.context.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;
}
初始化容器之后依次执行。
7、InitializingBean | PostConstruct
org.springframework.beans.factory.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;
}
javax.annotation.PostConstruct
这是一个注解和
InitializingBean
实现的目标是一样的,都是在Bean实例化之后调用。
这里的执行顺序InitializingBean
是优先注解执行的。
8、InstantiationAwareBeanPostProcessor
org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
return null;
}
}
InstantiationAwareBeanPostProcessor
是Bean实例化的后置处理器,也就是分别在Bean实例化前执行postProcessBeforeInstantiation()
,实例化之后执行postProcessAfterInstantiation()
, 还增加了PropertyValues
的扩展。由于
InstantiationAwareBeanPostProcessor
继承BeanPostProcessor
,所以还具备BeanPostProcessor
初始化的前后的功能。
9、BeanPostProcessor
org.springframework.beans.factory.config.BeanPostProcessor
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初始化前后执行的处理器。
实例化:实例化就是创建空对象,对象的属性还没有填充
初始化:实例化之后的对象,需要填充对象、赋默认值等操作。
注意点:由于
BeanPostProcessor
在BeanFactory生命周期内被Bean调用。如果通过BeanDefinitionRegistryPostProcessor
或其他 beanFactory.getBean(“XX”)的方式提前完成Bean的实例化,Bean就是在注册BeanPostProcessor
之前执行。定义的BeanPostProcessor
扩展点就无法“XX”的后置处理器(检测不到XX这个Bean)。A a = (A)configurableListableBeanFactory.getBean("a"); a.test2();
10、ApplicationRunner | CommandLineRunner
org.springframework.boot.ApplicationRunner
/**
* Interface used to indicate that a bean should <em>run</em> when it is contained within
* a {@link SpringApplication}. Multiple {@link ApplicationRunner} beans can be defined
* within the same application context and can be ordered using the {@link Ordered}
* interface or {@link Order @Order} annotation.
*
* @author Phillip Webb
* @since 1.3.0
* @see CommandLineRunner
*/
@FunctionalInterface
public interface ApplicationRunner {
/**
* Callback used to run the bean.
* @param args incoming application arguments
* @throws Exception on error
*/
void run(ApplicationArguments args) throws Exception;
}
org.springframework.boot.CommandLineRunner
/**
* Interface used to indicate that a bean should <em>run</em> when it is contained within
* a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined
* within the same application context and can be ordered using the {@link Ordered}
* interface or {@link Order @Order} annotation.
* <p>
* If you need access to {@link ApplicationArguments} instead of the raw String array
* consider using {@link ApplicationRunner}.
*
* @author Dave Syer
* @since 1.0.0
* @see ApplicationRunner
*/
@FunctionalInterface
public interface CommandLineRunner {
/**
* Callback used to run the bean.
* @param args incoming main method arguments
* @throws Exception on error
*/
void run(String... args) throws Exception;
}
ApplicationRunner
和CommandLineRunner
都是在项目启动完成之后执行的扩展点,但是ApplicationRunner
优先于CommandLineRunner
执行,两者处理参数的方式稍有不同。