Spring中常用扩展点以及执行顺序

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;

}

ApplicationRunnerCommandLineRunner 都是在项目启动完成之后执行的扩展点,但是ApplicationRunner 优先于CommandLineRunner 执行,两者处理参数的方式稍有不同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智_永无止境

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值